Thread: struct total size does not match the sum of the components

  1. #1
    Registered User
    Join Date
    Jan 2012
    Posts
    4

    struct total size does not match the sum of the components

    Hello,

    I usually develop in C for embedded platform (mplab C18 from microchip) and I use very often struct.

    I began to work on a project on a PC and I encounter one weird behavior which I don't understand :

    1st, when I do the sizeof(short, long, int and char) I get :

    short : 2 bytes
    long : 8 bytes
    int : 4 bytes
    char : 1 byte

    In the following struct, the total size from (sizeof) is 6 but if I do the sum of the size of the differents elements, it should sum 5.

    Code:
    typedef struct _test
    {
        unsigned char a;
        unsigned short b; // 2 bytes
        unsigned char c : 4;
        unsigned char d : 4;
        unsigned char e : 2;
        unsigned char f : 6;
    }test;
    so:

    a = 1 byte
    b = 2 bytes
    c + d = 1 byte
    e + f = 1 byte

    Why do the compiler add an empty byte somewhere ? At first, I though it was because the structs must be 2 bytes aligned but the following struct works fine :

    Code:
    typedef struct _test2
    {
      unsigned char a;
      unsigned char b;
      unsigned char c;
    }test2;
    
    the sizeof gives me 3 bytes which is right.
    If I only put 1 short in the structure, the structure is sized 2 bytes. but if I add an unsigned char, the size is not right (4 bytes)...

    I can't understand whis this behavior and How to bypass this ?

    Thank you for your help !
    Last edited by weebette; 01-27-2012 at 10:31 AM.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by weebette
    Why do the compiler add an empty byte somewhere ? At first, I though it was because the structs must be 2 bytes aligned
    Yeah, it is a matter of padding for alignment.

    Quote Originally Posted by weebette
    How to bypass this ?
    This is compiler dependent, but there may be a way to specify that you want the structure to be packed. Other than this, you can try declaring members such that padding is minimised, e.g., place the short before the char.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Alignment is about where something starts. The short b must start on a 2-byte boundary, so an extra byte is added after a.

    Try the following code with and without the pragma. As laserlight said, it's compiler dependent how to pack a struct, but this method may work for you. laserlight also mentioned rearranging the elements, which is probably more portable.

    Code:
    #include <stdio.h>
    
    //#pragma pack (1)
    
    typedef struct _test
    {
        unsigned char a;
        unsigned short b; // 2 bytes
        unsigned char c : 4;
        unsigned char d : 4;
        unsigned char e : 2;
        unsigned char f : 6;
    }test;
    
    int main() {
        test t = {1,2,3,4,1,2};
        *(&t.a + 1) = 255;
        printf("%d %d %d %d %d %d %d\n", t.a, *(&t.a+1), t.b, t.c, t.d, t.e, t.f);
        return 0;
    }
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  4. #4
    Registered User
    Join Date
    Jan 2012
    Posts
    4
    Thanks guys,

    You are right, it is a packing issue. When I add #pragma pack(1) the size is correct. But when I add a short in a structure, the size will always be a factor of 2 ( 4, 6...) why ?

    Code:
    struct _test3
    {
      unsigned short a;
      unsigned char b;
    }test3;
    the size will be 4. Why ?! And why there is no packing for an char[5] ?

    Thank you a lot for your help! Even if I don't fully understand at least I know how to solve the issue.

  5. #5
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    But when I add a short in a structure, the size will always be a factor of 2 ( 4, 6...) why ?
    Presumably so that if you make an array of these structs, the shorts will be properly aligned.

    And why there is no packing for an char[5] ?
    Because chars are single-byte aligned (on you machine, at least).
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by weebette
    But when I add a short in a structure, the size will always be a factor of 2 ( 4, 6...) why ?
    Maybe because if you have an array of such structs, the short member needs to be aligned on an appropriate boundary.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Jan 2012
    Posts
    4
    Thanks a lot for your help,

    I have a better understanding of the problem with a solution :-)

    I'm grateful!

  8. #8
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by weebette View Post
    I usually develop in C for embedded platform (mplab C18 from microchip) and I use very often struct.

    I began to work on a project on a PC and I encounter one weird behavior which I don't understand :
    Does this imply you are using C++ on the PC? If not, why did you post in the C++ section?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  9. #9
    Registered User
    Join Date
    Jan 2012
    Posts
    4
    I've putted this in C++ because yes, it is compiled with a C++ compiler.

    Thank you
    Last edited by weebette; 01-27-2012 at 05:00 PM.

  10. #10
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by weebette View Post
    Thanks guys,

    You are right, it is a packing issue. When I add #pragma pack(1) the size is correct. But when I add a short in a structure, the size will always be a factor of 2 ( 4, 6...) why ?
    It's not really right to say that it's "correct" or not. The compiler is enforcing the usual alignment requirements. The size of the structure will always be a multiple of the alignment of the LARGEST type inside the structure. So if you've got a 2-byte short in it, the size of the structure will be a multiple of 2, unless you specify that it should be packed.

    The size of a structure may depend on the order in which you put the components. For instance:

    Code:
    struct a
    {
        char a;
        short b;
        char c;
        short d;
    };
    Will take up 8 bytes, while the structure with a different order:

    Code:
    struct b
    {
        char a;
        char c;
        short b;
        short d;
    };
    will take only 6 bytes.

    The important thing to understand is there is no "issue" or problem here, there is nothing you need to "solve."
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  11. #11
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by brewbuck View Post
    The size of the structure will always be a multiple of the alignment of the LARGEST type inside the structure. So if you've got a 2-byte short in it, the size of the structure will be a multiple of 2, unless you specify that it should be packed.
    That's not quite true. The alignment boundaries are determined by the host system, and are often independent of the sizes of types.

    In fact, it is often the reverse: a 32-bit system will often align to 32-bit (or multiple) boundaries, and a number of basic types (integer, pointers) have a size that is a multiple of 32-bits. The defining parameter is the hardware architecture: how it addresses memory and sizes of registers. In practice, this parameter often (but not always) propagates through to requirements for sizes of basic types, and for their alignment.

    Quote Originally Posted by brewbuck View Post
    The size of a structure may depend on the order in which you put the components. For instance:
    True. The amount of padding implied by this is definitely related to the sizes of struct members, and their ordering. The precise relationship is system specific, though.

    A rule of thumb is often to place members in structs in decreasing size order (large ones first). This, in practice, often minimises the total size of the struct, by minimising requirements for padding. The challenge, however, is that sizes of basic types are implementation defined, and there is no guarantee of the relationships of sizes. For example, a float may be smaller, the same size, or larger than an int.

    Quote Originally Posted by brewbuck View Post
    The important thing to understand is there is no "issue" or problem here, there is nothing you need to "solve."
    Absolutely true.

    In fact, "solving" the problem can have unwanted effects. Alignment often gives performance benefits (accessing a value in a variable or field that is not aligned requires more instructions in software and/or more work by the processor). Another phenomenon is that, on some hardware, operations on unaligned variables trigger hardware fault conditions (which either need to be trapped and corrected, involving more overhead).
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Examining MBR and Printing Total Disk Size in Bytes
    By pantherman34 in forum C Programming
    Replies: 8
    Last Post: 04-30-2010, 03:27 PM
  2. Dynamic access to components of a struct
    By Kempelen in forum C Programming
    Replies: 1
    Last Post: 04-01-2009, 04:18 AM
  3. Replies: 5
    Last Post: 01-23-2007, 05:52 PM
  4. total size of a directory using C / C++
    By metthew in forum C Programming
    Replies: 1
    Last Post: 08-01-2002, 06:45 AM
  5. total size of dynamic memory allocated array
    By trekker in forum C Programming
    Replies: 10
    Last Post: 03-10-2002, 12:59 PM