Thread: sizeof union question

  1. #1
    * noops's Avatar
    Join Date
    Jun 2008
    Posts
    108

    sizeof union question

    I read that the sizeof a union is the largest of it's members. However, in the code below the union is larger than any of it's members. I only see this when using amd64 linux. I am compiling as gcc -o union.o union.c

    Code:
    #include <stdio.h>
    
    typedef union _NESTEDU
    {
    	long	l;
    	int	f;
    } NESTEDU;
    
    typedef struct _NOTHING
    {
    	int a;
    	int b;
    	int c;
    } NOTHING;
    
    typedef union _UNION
    {
    	int	i;
    	char	c;
    	NESTEDU	n;
    	NOTHING k;
    } UNION;
    
    int main()
    {
    	printf("struct/union sizeof testing\n");
    	printf("sizeof() int = %d\n", sizeof(int));
    	printf("sizeof() char = %d\n", sizeof(char));
    	printf("sizeof() UNION = %d\n", sizeof(UNION));
    	printf("sizeof() NESTEDU = %d\n", sizeof(NESTEDU));
    	printf("sizeof() NOTHING = %d\n", sizeof(NOTHING));
    
    	return(0);
    }
    And the output:
    Code:
    struct/union sizeof testing
    sizeof() int = 4
    sizeof() char = 1
    sizeof() UNION = 16
    sizeof() NESTEDU = 8
    sizeof() NOTHING = 12
    I am new to C so I may be missing something fundamental. Thanks for your help!

  2. #2
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    What is sizeof(long) on this machine? My guess would be that it's 8, in whcih case, to ensure that an array of UNION would be aligned correctly, a padding of 4 to make it a multiple of 8 is needed.

    Edit: of course, reading back the original printout, it says that NESTEDU is 8 bytes, so long must be 8 bytes.

    --
    Mats
    Last edited by matsp; 06-04-2008 at 01:57 PM.
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  3. #3
    * noops's Avatar
    Join Date
    Jun 2008
    Posts
    108
    Interesting. If what I am understanding is correct the size of any structure that contains a long on amd64 will need to be a multiple of 8.

    I've got a structure which by an unknown level of nesting contains a long but the structure is not a multiple of 8.

    This is part of large piece of code so I am trying to make a basic example which can reproduce this behavior.

    Thanks for your reply; I think it will help me to focus in on the root cause.

  4. #4
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Technically, the processor is CAPABLE of reading a 64-bit integer from an unaligned address. It's just less efficient, so unless you ask for it to be otherwise [with #pragma pack(x) in MS compilter or __attribute__((align(x))) in gcc], it should align 64-bit integers to an even multiple of 8. If it doesn't, then you've possibly found a compiler bug.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  5. #5
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by matsp View Post
    Technically, the processor is CAPABLE of reading a 64-bit integer from an unaligned address. It's just less efficient, so unless you ask for it to be otherwise [with #pragma pack(x) in MS compilter or __attribute__((align(x))) in gcc], it should align 64-bit integers to an even multiple of 8. If it doesn't, then you've possibly found a compiler bug.

    --
    Mats
    Then why does that affect unions but not structs? (since the NOTHING struct's size was 12).

  6. #6
    Registered User
    Join Date
    Oct 2001
    Posts
    2,934
    >Then why does that affect unions but not structs? (since the NOTHING struct's size was 12).
    NOTHING contains only ints (no longs).

  7. #7
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    a quick semi-hijack:
    Does the C/C++ standard say anything about sizeof(struct)? Or is it implementation defined?

  8. #8
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    Hello fair use!
    Quote Originally Posted by The C99 standard, 6.5.3.4
    3 ... When applied to an operand
    that has structure or union type, the result is the total number of bytes in such an object,
    including internal and trailing padding.
    4 The value of the result is implementation-defined....

  9. #9
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by cpjust View Post
    Then why does that affect unions but not structs? (since the NOTHING struct's size was 12).
    If you change NOTHING to be:
    Code:
    struct NOTHING
    {
       long a;
       int b;
    }
    then it's size will be 16 (on systems where long is 8 bytes).

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  10. #10
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    sizeof is an implementation-defined quantity for ANY type (int, double, structs, enums, unions, etc).

    The only practical guarantee for a union is that sizeof(union) IS NOT LESS THAN the size of the largest element of the union (as all elements co-exist in the same memory)

    The only practical guarantee for a struct is that sizeof (struct) IS NOT LESS THAN the sum of sizes of all elements of the union (as all elements must be distinctly represented).

    Since compilers often do things like padding (to optimise performance on machines by aligning data at key intervals), sizeof(union) typically exceeds the size size of its largest element, and sizeof(struct) typically exceeds the size of each of its component elements.

  11. #11
    * noops's Avatar
    Join Date
    Jun 2008
    Posts
    108
    Just an update that I 'discovered' what was causing the unexpected size. There is a #pragma pack(1) which is changing the alignment. I removed this and now the program does not crash. But I don't know enough to understand what else the change would impact.

  12. #12
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by noops View Post
    Just an update that I 'discovered' what was causing the unexpected size. There is a #pragma pack(1) which is changing the alignment. I removed this and now the program does not crash. But I don't know enough to understand what else the change would impact.
    #pragma pack(1) tells the compiler to pack the data "tight" (with no gaps between components in structs), rather than spacing it to the ideal alignment to give max processor speed.

    Depending on what those structs are used for, other components being passed those structs would potentially be affected by the now lacking pragma. I believe there are ways to "push" and "pop" the current pragma settings, so that you can do something like this:
    Code:
    #pragma pack(push)
    #pragma pack(1)
    ... stuff that _MUST_ be tightly packed. 
    ... 
    #pragma pack(pop)
    // Now we have the previous pragma pack() settings.
    The syntax for how you do this may be wrong, but I'm 99% sure that the concept is correct.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  13. #13
    Registered User
    Join Date
    Dec 2006
    Location
    Canada
    Posts
    3,229
    The only practical guarantee for a struct is that sizeof (struct) IS NOT LESS THAN the sum of sizes of all elements of the union (as all elements must be distinctly represented).
    Is it possible that the compiler optimizes out one (or more) of the unused elements?

    Same can be said for unions.

  14. #14
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by cyberfish View Post
    Is it possible that the compiler optimizes out one (or more) of the unused elements?

    Same can be said for unions.
    I doubt the compiler can actually [legally or logically] do that for any larger, more complex blocks of code. It may be possible that if you have a local struct within a small function that the compiler decides to store some fields in registers, and other components not used at all - but if you do sizeof() a struct that is local and never used, it will not say "zero".

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Question about the C99 standard (concerning union)
    By coyotte508 in forum C Programming
    Replies: 4
    Last Post: 05-07-2008, 02:57 PM
  2. Malloc,calloc..Sscanf.
    By ozumsafa in forum C Programming
    Replies: 22
    Last Post: 07-26-2007, 01:09 AM
  3. Question about sizeof()
    By spank in forum Linux Programming
    Replies: 12
    Last Post: 05-13-2007, 04:18 AM
  4. Cutting up an std::string
    By Shamino in forum C++ Programming
    Replies: 26
    Last Post: 04-04-2006, 11:02 AM
  5. sizeof() EZ question
    By V1P3R V3N0M in forum Windows Programming
    Replies: 15
    Last Post: 01-11-2003, 11:25 PM