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.
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
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)
//////////////////////////////////////////////////////////////////////// #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
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.