We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Look at this program:
/*------------------------------------------------------------------------------*/ #include <reg51.h> #include <stdio.h> typedef unsigned long uint32; typedef unsigned short uint16; typedef unsigned char uint8; #define MEMORY xdata #define StructMEMORY xdata typedef struct { uint16 lArg0; uint32 lArg1; } MyStruct; uint8 xdata * MEMORY lPtr; MyStruct StructMEMORY m; void MyInit() { m.lArg0=8; m.lArg1=2; lPtr=(uint8 xdata *)0xddd3; } void bug_0(MyStruct StructMEMORY *p) { static uint32 MEMORY lResults[4]; lResults[0]=((uint32)lPtr) + p->lArg1 + (uint32)(p->lArg0); lResults[1]=p->lArg1 + (uint32)(p->lArg0) + ((uint32)lPtr); lResults[2]=((uint32)lPtr); lResults[2]+=p->lArg1 + (uint32)(p->lArg0); lResults[3]=(uint32)(lPtr+p->lArg1 + (uint32)(p->lArg0)); if (lResults[0]==lResults[1] && lResults[1]==lResults[2] && lResults[2]==lResults[3]) printf("\nNo problems."); else for(;/* BUG */;); } void main() { MyInit(); bug_0(&m); } /*------------------------------------------------------------------------------*/
Change the following lines:
if (lResults[0]==lResults[1] && lResults[1]==lResults[2] && lResults[2]==lResults[3]) printf("\nNo problems."); else for(;/* BUG */;);
if (lResults[0]==lResults[1] && lResults[1]==lResults[2] && lResults[2]==lResults[3]) for(;/* BUG */;); else printf("\nNo problems.");
Stefan, problem not in endless loop, but in wrong compilation of this souce code by c51 compiler. Endless loop is only way to show what happens with execution of this program. By the way, bcc32.exe (from Borland Builder) compiles this program and exe works right.
"i used a 7.01 ver. of c51" Have you tried the latest version? Or at least looked at the Release Note to see if it mentions anything relevant...
"By the way, bcc32.exe (from Borland Builder) compiles this program and exe works right." Endian-ness?
Hello. Have you tried the latest version? No. Or at least looked at the Release Note to see if it mentions anything relevant... Yes, first of all I'm looked at release notes of c51 compiler, versions from 7.01 to latest and didn't find any topic, related to this problem. I have wrote to Keil support and will wait for responce.
In addition, c51 ver. 6.22 and earlier contains this bug too.
You said it "works" in Borland. Don't forget that Borland (in fact, the PC) has a different byte ordering ("Endian-ness") from C51. It may also introduce padding bytes. Check the Manual for both compilers.
I don't understand what you want to say, but I know aboud big and small endian. the next code:
{ long a1,a2,b,c,d; b=14444;c=3;d=4; a1=b+c+d; a2=b; a2+=c+d; if (a1!=a2) printf("\ncompiler bug."); }
By the way, look at assembler listing, generated from my source code and you will find interesting thing, the place where compiler hungs and generates wrong assembler directives: multiplication of lPtr by 2, and no actions on calculation of structure fields.....
"the next code: { long a1,a2,b,c,d; b=14444;c=3;d=4; a1=b+c+d; a2=b; a2+=c+d; if (a1!=a2) printf("\ncompiler bug."); } must not print "compiler bug" at any C compiler, if, sure, that compiler works with 32 bit data." I compiled this using 7.01 and it works fine. I've no idea what your first code example above is supposed to achieve, but why do you think that casting pointers to unsigned long is a legitimate (or reasonable) thing to do anyway? Stefan
Your example code is flawed such that any comparisons of its behaviour between different platforms are meaningless, because it makes assumptions about platform-dependent details, most importantly about what the result of an (int32) cast of a pointer object is. So whatever bcc did with this code is completely irrelevant. Next, you have some remaining implicit convertions sitting in there. Keil doesn't follow ANSI C implicit conversion rules unless explicitly requested. Did you turn on that option? You really should change the test in a way that lets you see *which* of the comparisons failed, and the actual values of the relevant variables.
"You really should change the test in a way that lets you see *which* of the comparisons failed, and the actual values of the relevant variables." Or just try stepping it in the simulator. You could do the same in the Borland debugger.
I simplified the first example into the following example, the difference do exist. But I tend to think it an issue of how to cast a pointer and don't make the complier confused.
typedef struct { uint16 lArg0; } MyStruct; uint8 xdata * MEMORY lPtr; MyStruct StructMEMORY m; void main() { uint32 MEMORY lResults[2]; m.lArg0=8; lPtr=(uint8 xdata *)0xddd3; // something wrong, when casting m.lArg0. lResults[0]=((uint32)lPtr) + ((uint32)(m.lArg0)); result = 1BBA6 // ok; result = DDDB lResults[1]=((uint32)lPtr); lResults[1] += ((uint32)(m.lArg0)); if (lResults[0]==lResults[1]) printf("\nNo problems."); else for(;/* BUG */;); }
27: lResults[0]=((uint32)lPtr) + ((uint32)(m.lArg0)); 28: // ok C:0x041D 90000A MOV DPTR,#m(0x000A) C:0x0420 E0 MOVX A,@DPTR C:0x0421 FE MOV R6,A C:0x0422 A3 INC DPTR C:0x0423 E0 MOVX A,@DPTR C:0x0424 FF MOV R7,A C:0x0425 E4 CLR A C:0x0426 FC MOV R4,A C:0x0427 FD MOV R5,A C:0x0428 900008 MOV DPTR,#lPtr(0x0008) C:0x042B E0 MOVX A,@DPTR C:0x042C FA MOV R2,A C:0x042D A3 INC DPTR C:0x042E E0 MOVX A,@DPTR C:0x042F FB MOV R3,A C:0x0430 CF XCH A,R7 C:0x0431 EB MOV A,R3 C:0x0432 CF XCH A,R7 C:0x0433 CE XCH A,R6 C:0x0434 EA MOV A,R2 C:0x0435 CE XCH A,R6 C:0x0436 E4 CLR A C:0x0437 FC MOV R4,A C:0x0438 FD MOV R5,A C:0x0439 EB MOV A,R3 C:0x043A 2F ADD A,R7 C:0x043B FF MOV R7,A C:0x043C EA MOV A,R2 C:0x043D 3E ADDC A,R6 C:0x043E FE MOV R6,A C:0x043F E9 MOV A,R1 C:0x0440 3D ADDC A,R5 C:0x0441 FD MOV R5,A C:0x0442 E8 MOV A,R0 C:0x0443 3C ADDC A,R4 C:0x0444 FC MOV R4,A C:0x0445 900000 MOV DPTR,#0x0000 C:0x0448 7170 ACALL C?LSTXDATA(C:0370) 29: lResults[1]=((uint32)lPtr);
Hello.
// something wrong, when casting m.lArg0. lResults[0]=((uint32)lPtr) + ((uint32)(m.lArg0)); result = 1BBA6 // ok; result = DDDB lResults[1]=((uint32)lPtr); lResults[1] += ((uint32)(m.lArg0));
lResults[0]=((uint32)lPtr) + p->lArg1 + (uint32)(p->lArg0); lResults[1]=p->lArg1 + (uint32)(p->lArg0) + ((uint32)lPtr);
lResults[2]=((uint32)lPtr); lResults[2]+=p->lArg1 + (uint32)(p->lArg0);
lResults[3]=(uint32)(lPtr+p->lArg1 + (uint32)(p->lArg0));
……. uint8 XDATA * DATA RAMDISK; ……. /* write to file */ void rdisk_fwrite(file_entry XDATA *mfile, uint8 XDATA *buff, uint16 len) { uint16 DATA i; #ifdef __SELECT_ADAPTER_CONFIG uint8 XDATA * DATA ptr; ptr=&RAMDISK[mfile->file_start_ram_index+mfile->file_len]; i=len; while (i--) *ptr++ = *buff++; #else # ifdef __SELECT_TERMINAL_CONFIG MEMORY_UINT DATA ptr; uint8 DATA lByte; /* >>>>>>>>>>>>>>>>>>>>>here the simulator reported strange result in 'ptr' variable */ ptr=((MEMORY_UINT)RAMDISK)+mfile->file_start_ram_index+(MEMORY_UINT)mfile->file_len; /* >>>>>>>>>>>>>>>>>>>>>here the simulator reported strange result in 'ptr' variable */ i=len; while (i--) { lByte=*buff++; RAMDISK_put(ptr, lByte); ptr++; } # endif #endif buff-=len; update_crc(buff, len, &mfile->file_csum); mfile->file_len+=len; }
Sorry, but C51 Version 7.08 compiles the code OK. Maybe you have some special compiler settings or so, but the code prints OK. It seems that the problem has been solved already in Version 7.04 in context with the "integer promotion problems with combined pointer and char arithmetic". Refer also to the Release Notes.