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

  • Do you mean it gives compiler errors or that the program doesn't work properly?

    Quite honestly, the code is such a mess of typedefs and indirection I'm surprised you're even sure what it is supposed to do.

    Stefan

  • I cannot even begin to fathom what it is you are trying to achieve let alone what you source code actually does. Whatever it is you are trying to do, I am quite sure there will be a better way to do it.

    Just a wild stab in the dark, but only one of your pointers is explicitly directed to a particular memory type:

    typedef A xdata * PAx;
    
    All the other pointers are going to be generic, could this be at the root of the problem?

  • This code contains extracted macros:

    #define STRUCT_MEMBER_OFFSET( s, m ) ((PCHAR)&(s).m) - (PCHAR)&(s))
    #define _A  (*(PAx)(&cAOld))
    #define _Ax (*(PA)(&cAOld))
    
    #if     BUG_TEST == 0   //Normal
    int l1 = (PCHAR)&_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)
    int l1 = (PCHAR)&_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
    #endif
    
    

    This need to describe info of structs:
    code UINT StructInfo_A_MembersOffset[] = {
        STRUCT_MEMBER_OFFSET( _A, nI ),
        STRUCT_MEMBER_OFFSET( _A, nJ ),
    }
    code STRUCT_INFO StructInfo_A = {
        &_A,
        StructInfo_A_MembersOffset
    };
    

  • Firstly, does the offsetof() macro in stddef.h not work too?

    Secondly, you did not say which memory model you are using. I could imagine BUG_TEST #1 and #2 failing if you are using the small model.

  • 1. To use offsetof() I must known type of _A, that additional way for future errors.
    2.
    DATA - small
    CODE - large
    But why program options should influence on it stability?

  • "But why program options should influence on it stability?"

    I was just thinking that with cAOld being in DATA memory (small model) and your macros are taking its address and treating it like it's in XDATA memory, the compiler might have trouble with that. Dunno, just a thought.

  • Yes, but cAOld in xdata memory. This my typing error while writing this message thread.

    I wanted to write:
    "xdata A_ODL cAOld;"

    Sorry.

  • OK, then the typedef's and macros have a bit of a mix of generic pointer and memory-specific pointer casting and dereferencing. I wonder if trying to make things a bit more consistent would help.

    I also wonder if some of the macros are going to evaluate to a runtime thing versus a compile-time thing. That's why offsetof() works -- because it's always casting a constant as an address.

    Note: I have not been trying any of this during the discussion and have been "shooting from the hip" as I quickly prepare to leave for the day.

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

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