This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

may be a BUG in Keil c51 ? (32bit calculations)

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);
}
/*------------------------------------------------------------------------------*/

Try to compile it and run it. You will get the endless loop.

i used a 7.01 ver. of c51

Project sets:
Target i8051AH
[v]Use on-chip rom
off-chip xdata memory: 0x0000-0x01ff
memory model: small, code rom size: small

Michael S.

Parents
  • 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.

Reply
  • 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.

Children
  • "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 */;);
    }
    

    This is the snapshot of what the compiler did. R0, R1 is wierd.
    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);
    

    Frank Hu

  • 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));
    

    I also had it in view of when has placed the first initial text on C in heading of a theme. The others lResults have been added to show,
    In - the first:
    lResults[0]=((uint32)lPtr) + p->lArg1 + (uint32)(p->lArg0);
    lResults[1]=p->lArg1 + (uint32)(p->lArg0) + ((uint32)lPtr);
    
    From change of places composed the result has changed!!!! This fact can be seen at step-by-step performance in a simulator. lResults [0] and lResults [1] are not equal.

    In - the second:

    At a partition of compound addition on parts, the compiler has generated the machine code calculating correct result:
    lResults[2]=((uint32)lPtr);
    lResults[2]+=p->lArg1 + (uint32)(p->lArg0);
    

    In – the third:
    Addition the pointer and integer (such operation is allowable in language C and for c51 too it is allowable) and then reduction of the received pointer works and, strangely enough, too gives correct result. Here it is possible to tell: to result the pointer in the integer type it is impossible, what it is absurdity but then the compiler should make at least the warning at compilation, however Keil c51 it has not made (I can has not included what or options or #pragma ?):
    lResults[3]=(uint32)(lPtr+p->lArg1 + (uint32)(p->lArg0));
    

    And the most important, I have found out this mistake, debugging the project for the device on at89c55, there there was such sequence of a code:
    …….
    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;
    }
    
    In the specified place the simulator showed 'wild' result. When I have spread out addition on components, I have received that is necessary on sense of the program.

    And already at house I have outlined the small project on Keil C and have seen the same mistakes, have then decided to experiment with the order of calculation of expression and as a result the initial source code which I have placed in heading of a theme has turned out.


    I want to thank to all participating in discussion, probably it is fast and with the answer on this problem support@keil.com will come and will be solved, where also what particularly the mistake is in c51, what to deny already there is no sense as it seems to me.

  • 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.