A bug caused by a local variable which just named "a" in Keil C51V961

My keil is the latest version C51V961.

The code is very simple:

#include "reg52.h"
#include "stdio.h"
#include "intrins.h"

void uart_init()
{
	SCON = 0x52;
	TMOD = 0x20;
	TH1  = 0xfd;
	TL1  = 0xfd;
 	TR1  = 1;
}

void main()
{	
	unsigned int a=17; // note: the name "a" caused the bug
	unsigned int b;
	uart_init();
	for(b=2;b<=a-1;b++)
	{
		if(a%b==0)
			break;
	}
	if(b<a)
		printf("%d is not a prime number",a);
	else
		printf("%d is a prime number",a);
	while(1);
}

The steps to repeat the bug:

1. create a at89s52 project.

2. copy and paste the above code to the main.c file of the project.

3. compile the project, and click the "start/stop debug session" button to launch the debug session, then click the "step over" button, watch the value of local variable "a" and "b", everything is OK. 

4. stop the debug session.

5. click the "start/stop debug session" button again, then click the "step over" button, watch the value of local variable "a" and "b", then the values change as unexpected.

Conclusion:
1. When the name of the local variable is “a”, only the result of the first compilation is correct. The second and subsequent compilation results are incorrect.
2. If I move variables "a" and "b" outside the main() function to become global variables, then everything will OK and there will be no more bugs.

Please observe the GIF animation:

(P.S. Please "save as" this gif if it is small in the webpage)

And the project I used:

test2.zip

Parents
  • Although this post is almost one month old, I'd like to clarify the behavior of our tools:

    I'm not sure if I understand correctly: for the reserved words in the link you provided, neither assembly nor C51 program can be used as variables, and even lowercase letters cannot be used. For example, 'A' is the reserved symbol for the Ax51 assembler, so the programmer can not use 'A' or 'a' as a variable name, even in C51 program.

    No, that's not true. Usually, you can use variable names like 'a' and 'b' in your C source code and the compiled code will still be correct. There are restrictions when you compile a C-source code with the compiler to an assembly source code and then to an executable code with the assembler. This is only necessary when you want to use inline assembler code in a C module.

    What you have demonstrated in your video/gif, is a side effect in the debugger, but the application must work as expected. In your first debug session, you add 'a' and 'b' at a time when the program counter 'PC' is within the same function as these local variables. The µVision debugger uses the current scope and finds these two local variables and displays them correctly.
    When you start the debug session a second time, the two variables are automatically added to the watch window (see the WS commands in the command window). At this time the PC is still on the reset address and the µVision debugger only finds the processor registers A and B (global symbols, and debug symbols in OMF51 format are not case-sensitive) and displays them in the watch window.

    When you right-click the variables in the C source code and then select 'Add to Watch Window', the fully qualified variable name (with function name) would be taken to the watch window and then you would not run into this issue. 

Reply
  • Although this post is almost one month old, I'd like to clarify the behavior of our tools:

    I'm not sure if I understand correctly: for the reserved words in the link you provided, neither assembly nor C51 program can be used as variables, and even lowercase letters cannot be used. For example, 'A' is the reserved symbol for the Ax51 assembler, so the programmer can not use 'A' or 'a' as a variable name, even in C51 program.

    No, that's not true. Usually, you can use variable names like 'a' and 'b' in your C source code and the compiled code will still be correct. There are restrictions when you compile a C-source code with the compiler to an assembly source code and then to an executable code with the assembler. This is only necessary when you want to use inline assembler code in a C module.

    What you have demonstrated in your video/gif, is a side effect in the debugger, but the application must work as expected. In your first debug session, you add 'a' and 'b' at a time when the program counter 'PC' is within the same function as these local variables. The µVision debugger uses the current scope and finds these two local variables and displays them correctly.
    When you start the debug session a second time, the two variables are automatically added to the watch window (see the WS commands in the command window). At this time the PC is still on the reset address and the µVision debugger only finds the processor registers A and B (global symbols, and debug symbols in OMF51 format are not case-sensitive) and displays them in the watch window.

    When you right-click the variables in the C source code and then select 'Add to Watch Window', the fully qualified variable name (with function name) would be taken to the watch window and then you would not run into this issue. 

Children
No data