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

C51bugs

This code generate 2 bugs:

#define BUG_TEST 0

typedef char * PCHAR;

typedef struct {
    int I;
    int J;
} A_OLD;

typedef struct {
    int nI;
    int nJ;
} A, *PA;
typedef A xdata * PAx;

A_OLD cAOld;

#if     BUG_TEST == 0   //Normal
int l1 = (PCHAR)&(*(PA)(&cAOld));                                               //Get address of struct
int l2 = ((PCHAR)&((*(PA)(&cAOld)).nI) - (PCHAR)&(*(PA)(&cAOld)));              //Calc offset of member
#elif   BUG_TEST == 1   //Cann't initialize
int l1 = (PCHAR)&(*(PAx)(&cAOld));                                              //Get address of struct
#elif   BUG_TEST == 2   //General fault C51
int l2 = (unsigned int)((PCHAR)&((*(PA)(&cAOld)).nI) - (PCHAR)&(*(PA)(&cAOld)));//Calc offset of member
#endif

Parents
  • To use offsetof() I must known type of _A, that additional way for future errors.

    I'm not sure you are saving yourself any future grief with the macros you are using now. You still have to know the type of the structure to calculate the offset. But, the _A macros

    #define _A (*(PAx)(&cAOld))

    are forcing the structure to be a particular type, and you'll get errors if the actual struct used isn't of that type. offsetof() will break when you change the name of your structure; but then, so will _A and thus STRUCTURE_MEMBER_OFFSET. To each his own, I suppose.

    Let's all pause for a moment of silence to wish for the typeof() operator (once again). Thank you.

    One problem here is that "int" is 16 bits in Keil, and that's not big enough to hold a generic pointer. It's big enough for a _difference_ of pointers (ptrdiff_t), and big enough for any offset in a structure (size_t). But you can't stuff any pointer into an int, only the memory-specific pointers.

    What version of the compiler are you using? With 7.05:

    For BUG_TEST == 1, I get warning C260, "pointer truncation". Seems appropriate.

    For BUG_TEST == 2, I get no error at all. Executing the code seems to produce the right answer for nI (0) and nJ (2).

    Most of the time, it's likely best to be explicit with your memory type qualifiers. Don't depend on the memory model to get them right.

Reply
  • To use offsetof() I must known type of _A, that additional way for future errors.

    I'm not sure you are saving yourself any future grief with the macros you are using now. You still have to know the type of the structure to calculate the offset. But, the _A macros

    #define _A (*(PAx)(&cAOld))

    are forcing the structure to be a particular type, and you'll get errors if the actual struct used isn't of that type. offsetof() will break when you change the name of your structure; but then, so will _A and thus STRUCTURE_MEMBER_OFFSET. To each his own, I suppose.

    Let's all pause for a moment of silence to wish for the typeof() operator (once again). Thank you.

    One problem here is that "int" is 16 bits in Keil, and that's not big enough to hold a generic pointer. It's big enough for a _difference_ of pointers (ptrdiff_t), and big enough for any offset in a structure (size_t). But you can't stuff any pointer into an int, only the memory-specific pointers.

    What version of the compiler are you using? With 7.05:

    For BUG_TEST == 1, I get warning C260, "pointer truncation". Seems appropriate.

    For BUG_TEST == 2, I get no error at all. Executing the code seems to produce the right answer for nI (0) and nJ (2).

    Most of the time, it's likely best to be explicit with your memory type qualifiers. Don't depend on the memory model to get them right.

Children
  • I frequently have the same problem. Here is an example of a header file that I use for generating IDs of text strings that are array subscripts to a table of text messages (which may need translation to other languages). The same method can be used with 'offsetof' to generate a table of indexes.

    //  +--------------------------------------------------------------------------+
    //  |   TxtTable.h                                                             |
    //  |                                                                          |
    //  |   If "InModTxtTable" is defined, initializations are performed. To use   |
    //  |   this feature, "include" the file twice.  The first time before the     |
    //  |   definition of "InModTxtTable", the second time after the definition.   |
    //  |                                                                          |
    //  +--------------------------------------------------------------------------+
    
    
    #ifdef  _txttableh
        #ifdef  InModTxtTable
            #undef _txttableh
        #endif
    #endif
    
    #ifndef _txttableh
    #define _txttableh
    
    #ifdef  InModTxtTable
        #define TxtItem(Id, Text) Text
    
        code char code *TxtString[] = {
    #else
        #define TxtItem(Id, Text) Id
    
        enum TextStringIds {
    #endif
    
    
    /* --  Text Strings for language conversion  -------------------------------- */
    
    TxtItem ( tidOpErrBase,     "NoneDetected"      ),
    TxtItem ( tidMemFailure,    "RAM Failure"       ),
    TxtItem ( tidSigFailure,    "Params Reset"      ),
    TxtItem ( tidE2MemoryErr,   "E2 Mem Fail"       ),
    TxtItem ( tidLocalHBusErr,  "Loc Bus Fail"      ),
    TxtItem ( tidSystemHBusErr, "Sys Bus Fail"      ),
    
    /*----------------------------------------------------------------------------*/
    
    #ifdef InModTxtTable
        (void *)0
    #else
        MaxTextStringId
    #endif
    };
    
    #undef  TxtItem
    
    #endif
    

  • Final report:
    --------------------------------------------

    Compiler:

    --------------------------------------------

    C51 COMPILER V7.04   DATA                                                                  03/15/2003 10:49:27 PAGE 1
    
    
    C51 COMPILER V7.04, COMPILATION OF MODULE DATA
    OBJECT MODULE PLACED IN data.OBJ
    COMPILER INVOKED BY: D:\MCONTROL\KEIL704\C51\BIN\C51.EXE data.c OPTIMIZE(SIZE) DEBUG OBJECTEXTEND DEFINE(ENABLE_EPROM,LA
                        -NG=UKR,DEBUG,_RESTAURANT_MODE,xTECH_ROM,xPRINT_LOGO_FROM_ROM) CODE LISTINCLUDE SYMBOLS PRINT(.\obj\data.lst) PREPRINT(.                    -obj\data.i)
    
    
    --------------------------------------------

    Source:

    --------------------------------------------
    ////////////////////////////////////////////////////////////////////////
    #define BUG_TEST 2
    
    typedef char * PCHAR;
    typedef char xdata * PCHARx;
    
    typedef struct {
        int I;
        int J;
    } A_OLD;
    
    typedef struct {
        int nI;
        int nJ;
    } A, *PA;
    typedef A xdata * PAx;
    
    xdata A_OLD cAOld;
    
    #define _STRUCT_MEMBER_OFFSET( s, m ) (((PCHAR)&(s).m) - (PCHAR)&(s))
    #define _Ax (*(PAx)(&cAOld))
    #define _A  (*(PA)(&cAOld))
    
    #if     BUG_TEST == 0   //Normal
    PAx l1 = (PAx)&_A;                                      //Get address of struct
    int l2 = _STRUCT_MEMBER_OFFSET( _A, nI );               //Calc offset of member
    #elif   BUG_TEST == 1   //Cann't initialize (compiler error)
    PAx l1 = &_Ax;                                          //Get address of struct
    #elif   BUG_TEST == 2   //General fault C51 (system error)
    int l2 = (unsigned int)_STRUCT_MEMBER_OFFSET( _A, nI ); //Calc offset of member
    #elif   BUG_TEST == 3   //Normal
    int l2 = (unsigned int)(ptrdiff_t)_STRUCT_MEMBER_OFFSET( _A, nI ); //Calc offset of member
    #endif
    
    --------------------------------------------

    Results:

    --------------------------------------------
    /*
    BUG_TEST = 0: OK

    BUG_TEST = 1: error C247: non-address/-constant initializer

    BUG_TEST = 2: General fault
    Программа C51 вызвала сбой при обращении к странице памяти
    в модуле C51.EXE по адресу 0167:0045439a.
    Регистры:
    EAX=00000905 CS=0167 EIP=0045439a EFLGS=00000206
    EBX=004c082d SS=016f ESP=0074f364 EBP=0074f3a4
    ECX=007b0f44 DS=016f ESI=007b12f3 FS=471f
    EDX=007b0f44 ES=016f EDI=00770002 GS=0000
    Байты по адресу CS:EIP:
    80 38 01 0f 85 8f 00 00 00 66 8b 40 06 8b fe 66
    Содержимое стека:
    00000000 0077b29c 004c0810 00454668 007b11ab 0077b29c 00000000 007b108c 00454b75 0077b29c 00760008 007b108c 004c0810 007b108c 004c0810 00455489

    BUG_TEST = 3: OK
    */

    --------------------------------------------

  • The problem will be fixed in the next version (7.07) that will come out in a few weeks. If you need a patch before that, send an email to: support.intl@keil.com.