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

printing sizeof() values

I'm trying to print out sizeof() values for some of my structures. They are coming out incorrect. Here is a small table in which I've done this on different platforms:

Linux : sizeof(TChannel) = 1460
Windows: sizeof(TChannel) = 1460
8051 : sizeof(TChannel) = 1361

Are there byte-alignment issues perhaps? I have both Linux and Windows defaulting to a 1-byte boundary for byte alignment in structures. Does the 8051 default to something different?

Here's my code for the 8051:
Debugf( "sizeof(TChannel) = %u\r\n", sizeof( TChannel ) );

I've tried %u, %d, %lu, %bu, %X but can't get the right value. Here's my Debugf() function in case that might be messing things up:

void Debugf(BYTE* format, ...)
{
#ifdef DEBUG
xdata BYTE buf[64];
va_list arglist;
va_start (arglist,format);
vsprintf(buf,format,arglist);
va_end (arglist);
SendSerialData( buf, strlen( buf ) );
#endif
}

I don't think the problem is in my SendSerialData() function as that seems to work well.

Any ideas?

  • nevermind, discovered I must CAST sizeof() to unsigned int for it to work.

  • nevermind, discovered I must CAST sizeof() to unsigned int for it to work.

  • You don't show the truly important detail: the definition of that struct.

    Either way, I strongly doubt that a lack of a cast could ever change a value from 1460 to 1361. So the true difference is quite certainly elsewhere.
    You should probably check the alignment on the PC side more carefully, and compare it to the "real" design size of your struct.

  • If your structure contains some pointer, it is normal that sizeof differs. For Windows and Linux, pointeur is 4 bytes. For 8051, generic pointeur is 3 bytes and specific pointeur is 1 byte (idata, data, pdata) or 2 bytes (code, xdata).

  • After making sure my structs on Windows were byte aligned with:

    #ifdef _WINDOWS_
    #pragma pack (1)
    #endif

    I also discovered that in Windows a BOOL is 4 bytes, which was defined as an unsigned char on 8051 (by me), which is only 1 byte.

    And a UINT on windows is 4 bytes, which is defined as unsigned int on 8051 (by me) and it's only 2 bytes.

    #ifndef _WINDOWS_
    typedef unsigned char BYTE;
    typedef unsigned int UINT;
    typedef unsigned long ULONG;
    typedef unsigned char BOOL;
    typedef unsigned int WORD;
    typedef unsigned long DWORD;
    typedef unsigned int USHORT;
    #endif

  • After making sure my structs on Windows were byte aligned with:

    #ifdef _WINDOWS_
    #pragma pack (1)
    #endif

    I also discovered that in Windows a BOOL is 4 bytes, which was defined as an unsigned char on 8051 (by me), which is only 1 byte.

    And a UINT on windows is 4 bytes, which is defined as unsigned int on 8051 (by me) and it's only 2 bytes.

    #ifndef _WINDOWS_
    typedef unsigned char BYTE;
    typedef unsigned int UINT;
    typedef unsigned long ULONG;
    typedef unsigned char BOOL;
    typedef unsigned int WORD;
    typedef unsigned long DWORD;
    typedef unsigned int USHORT;
    #endif

  • ...in Windows a BOOL is 4 bytes...
    ...UINT on windows is 4 bytes...


    By "Windows," I presume you mean Win95/98/NT/2k/XP..?

    All of these are 32-bit systems, so 4 bytes should come as no surprise whatsoever - it's 32 bits!!

    That's why I keep saying that names like "UINT" should be avoided - they convey no information at all as to the intended size of the type.
    I always use names like U8, U16, U32 so that the size is instantly, clearly, and unambiguously obvious at a glance.


    BTW: The internal representation of 'C' data types is primarily an issue for the Compiler rather than the operating system - so rather than saying "in Windows..." you should say "in MSVC..." or whatever.
    (Having said that, of course, it makes sense for the Compiler to follow the "natural" representation of the underlying architecture...)

  • As you found, sizeof should be cast but do you not know that the compiler is free to insert pad bytes in structs *after* the first element for alignment purposes? On the 8051, aligment is to 1 byte thus all structs are "packed". On a 16-bit machine typically padded to 2 bytes, with a 32-bit machine padding to 4 usually.

  • Hey! U8, U16, U32 are mine! All mine! :-)

    I wonder why the OP didn't typedef Bool to bit a bit instead of char?

  • I wonder why the OP didn't typedef Bool to bit a bit instead of char?


    I didn't do this because I couldn't get the type 'bit' to be declared in xdata. The compiler choked (I forget the error message).

    And since I have boolean values in my structures, which are in xdata, BOOL was defined as unsigned char.


    On the 8051, aligment is to 1 byte thus all structs are "packed". On a 16-bit machine typically padded to 2 bytes, with a 32-bit machine padding to 4 usually.


    Yes, the following will force MSVC (on a 32-bit Intel machine) to align to 1 byte boundaries, to match that of the 8051.

    #ifdef _WINDOWS_
    #pragma pack (1)
    #endif

    structs go here

    As you might have guessed, this is a common header file that both my GUI on Windows and the firmware on the 8051 share, so I can transfer these structures back and forth via the serial port. And yes, I do all the endian conversion on the GUI side; it works just fine.

  • I didn't do this because I couldn't get the type 'bit' to be declared in xdata. The compiler choked (I forget the error message).

    Of course it choked, bit data is a not only an 8051 type but a memory space, that space is at DATA address 0x20 and extends for some number of bytes that can be treated as true bit types. It is a contradiction to attempt an XDATA bit var. For structs (or do you mean C bit-fields?) you must use the type unsigned char for the next most efficient access (remember, you pay a penalty for the signed versions).


  • ISO C99 has finally gotten around to supplying some standard types with specific sizes. <inttypes.h> will give you int8_t, uint8_t, and so on. It also provides some "half-open" types, so you can express the notion of "most convenient/fastest unsigned integer type as long as it's at least 16 bits wide" (uint_least16_t/uint_fast16_t), uintmax_t, intptr_t, conversion and limits macros galore, and so on.

    Not quite as terse as my favorites (U8, etc), and we're all already used to our home-grown solutions, but support should be available on multiple platforms without having to define them yourself.

    They also add a "bool" type, which of course introduces all sorts of interesting questions for every platform provider as to how it's implemented.

  • "On a 16-bit machine typically padded to 2 bytes, with a 32-bit machine padding to 4 usually."

    I'm sure Mark knows this already, but for the general reader:

    It can get even more complicated than that; eg, a 32-bit machine may be happy with unaligned 8-bit values, 16-bit values aligned on any even boundary, but 32-bit (or larger) values may need the 4-byte alignment.
    The compiler may allow you to override this and 'pack' your structures, but that may bring a serious performance hit!!

    As I keep saying, this is where it is essential that you fully read and understand the compiler Manual - particularly the section on internal data representation!