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

Problem using sizeof() with element of struct

Hi all! I am experiencing the following problem:

sizeof(EDA.stPARAM) returns 0x80 with CA.exe V2.41 which in my opinion is the correct result, but with CA.exe V2.50a it returns 0x82. Can somebody explain this behaviour to me? Code sample is included below:

file eda_st.inc:

struct
{

byte ubFree_0000h[16] ;/* 000h-00Fh: */

byte ubFree_0010h[16] ;/* 010h-01Fh: */

byte ubFree_0020h[16] ;/* 020h-02Fh: */

byte ubFree_0030h[16] ;/* 030h-03Fh: */

byte ubFree_0040h[16] ;/* 040h-04Fh: */

byte ubFree_0050h[16] ;/* 050h-05Fh: */

byte ubFree_0060h[16] ;/* 060h-06Fh: */

byte ubFree_0070h[16] ;/* 070h-07Fh: */

}stPARAM;

struct
{

byte VER_HWVers ;/* 000h: */

byte ubFree_0000h[127] ;/* 001h-07fh: */

}stABGLEICH;

----------------------
file eda_usr.h:

typedef struct
{

#include "eda_st.inc" // struct mit Parametern

} EDA_sttyDAT;

extern EDA_sttyDAT EDA;

----------------------
file eda_usr.c:

#define TAR_RAMCOPY 0x40001000

EDA_sttyDAT EDA __at(TAR_RAMCOPY);// RAM-Kopie

Parents
  • The struct members have a length of 128 bytes each

    That's what you think. The compiler thinks otherwise.

    The problem is one level deeper: it's in the original assumption that there is such a thing as a "correct" sizeof() figure for a C struct. There isn't. The size of a struct depends on things outside the source code.

Reply
  • The struct members have a length of 128 bytes each

    That's what you think. The compiler thinks otherwise.

    The problem is one level deeper: it's in the original assumption that there is such a thing as a "correct" sizeof() figure for a C struct. There isn't. The size of a struct depends on things outside the source code.

Children
  • I see this in a more practical way. The project was set up with V2.41 and everything worked fine. Then we switched to V2.50a and out of a sudden the sizeof expression doesn't work correctly anymore. I have checked the size of the EDA struct in the MAP file and it is exactly the size I would have expected. The sum of the sizeof over all struct members simply doesn't match the occupied memory space. The sum of the elements is by six bytes larger than the overall size. The original struct has three members and the sizeof expression evaluates to the expected size plus 2 Bytes for every member. I really think this is strange behaviour.

  • Maybe the compiler want to add an extra byte of empty data at end of struct, to make sure that it is allowed to do a 16-bit access to the last byte without overflowing into unknown data space.

    But since 1 bytes of overflow protection makes the struct incorrectly aligned, the compiler then has to add more padding.

    Never depend on a specific size of a data structure.

    By the way, why are you plaing with include files when defining your struct? It doesn't help readability.

  • I just noticed that I used an old MAP file. The size of the EDA struct DOES match the sum of the sizeof values. But I still don't understand why there is a different behaviour in compiler version 2.51a in comparison to version 2.41. Thanks to all for your advice.

  • I see this in a more practical way.

    No. You see it in an incorrect way.

    the sizeof expression doesn't work correctly anymore.

    Actually, the sizeof operator is working quite fine. It's your expectations that don't work.

    As I explained before, the error here is in the expectation that there should be a single number that can be called "the" correct sizeof() value. The size will be what the compiler thinks it should be. No more, no less.

  • Embedded compilers usually have "pad" or "pack" pragmas or options to control alignmenet and structure padding for those cases where it makes a difference. In the case of RealView, there's a __packed qualifer to be used in declarations.

  • Not only embedded compilers.

    Most compilers has it, since most C/C++ compilers are intended to allow systems programming. In some situations it is faster to use packet data structures instead of having to write the data byte-for-byte when writing graphics drivers or TCP/IP stacks etc.

  • Sorry to "sort of hijack" this thread, but...

    On the subject of the __packed qualifier, has anyone else noticed the overhead that this appears to incur in the Keil ARM compiler ?

    I haven't had time to do extensive testing, but my initial impression is that all accesses to members of __packed structures appear to be made using function calls. This may not be an issue in many cases, but might be worth experimenting with if time and/or space are critical.

    Regards

    David.

  • Yes, __packed do require a lot of extra code, since the compiler has to generate code - or call helper functions - to read the data as 8-bit entitires and then build any 16-bit, 32-bit or 64-bit variables from these individually read bytes.

    That is the reason _why_ compilers normally align all data, and why linkers also knows how to add padding to maintain align.

    Some processors - such as x86 - have a memory controller that supports "hiding" of non-aligned access. The memory controller can do two 32-bit reands, sift through the data and return a single 32-bit unaligned value to the processor core. The only cost being the potential pipeline stall while waiting for an extra memory access.

    Most ARM processors have very stupid memory controllers. They tend to issue an exception or return bogus data for nonaligned data. The Keil compiler does not have any idea about exactly how stupid the memory controller is for a specific chip. The behaviour may even differ between different memory areas, i.e. unaligned access to special function registers for a serial port may give different behavour than unaligned access to the flash or the RAM.

    In short - the compiler just have to add "safe" code. And safe code is code that reads the data one byte at a time. And such code is larger - a lot larger - than normal native memory accesses.