1

I have a structure of size 48 bytes and recently added another structure inside it which was of size 20 bytes ; so the total size of structure became 68 bytes. (all the members were unsigned int)

typedef struct{
           ...
           ...
           unsigned long long a1;
           struct s2
           }s1 ;

S1 structure is an array ; if s1 is incremented using s1++ then it is observed that s1 is incremented with 72 bytes instead of 68 bytes. Surprisingly if the struct s2 is removed from s1 everything works properly i.e., s1 gets incremented with 48 bytes. Any pointers on the reason would be helpful.

lxusr
  • 987
  • 3
  • 16
  • 28
  • Are you on a 64 bit platform ? – Paul R May 24 '12 at 14:25
  • Looks like your platform wants to align struct types to 8 bytes, rather than 4. What does `sizeof (s1)` evaluate to? – John Bode May 24 '12 at 14:27
  • I am using 32-bit platform only; using gcc version 4.1.2 ; – lxusr May 24 '12 at 14:29
  • 1
    `s1` is a type, not a variable. You can't increment types. Can you post code that more accurately describes what you do? Though it seems like people managed to guess it anyway. – ugoren May 24 '12 at 14:30
  • One question: How do you know that the second structure is 20 bytes? Padding can happen *inside* of a structure. – ArjunShankar May 24 '12 at 15:05
  • possible duplicate of [Why isn't sizeof for a struct equal to the sum of sizeof of each member?](http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member) – Bo Persson May 24 '12 at 16:26
  • There was an unsigned long long element inside s1 ; probably the reason for the structure to get aligned to 8 bytes and hence it was padded with 4 bytes. I cannot remove unsigned long long element or change it to unsigned long ; Can the alignment be forced to 4 byte using align(4) ? Is it a good option ? – lxusr May 25 '12 at 07:14
  • gcc version is not supporting __attribute__((aligned(4))) ; The structure is not getting aligned to 4. Seems like attribute(packed) is what I have to use for GCC versions prior to gcc-4.4.1 where this feature is broken. Thanks all. – lxusr May 30 '12 at 10:42
  • ) What is struct s2? 2) **why is there no semicolon after `struct s2`** ? 3) what is "incrementing a structure" ? – wildplasser May 30 '12 at 10:45

3 Answers3

3

You don't say what compiler or platform you're using, but most likely the compiler is adding alignment bytes to make the struct align on 8-byte boundaries. This is quite common.

Carey Gregory
  • 6,836
  • 2
  • 26
  • 47
  • This seems odd and in perhaps non-conformant (I'm pretty sure it would break some cases of the rule about structures with matching initial members). – R.. GitHub STOP HELPING ICE May 24 '12 at 14:31
  • 1
    @R.. Why do you think this is odd or non-conformant? (Nearly?) every compiler adds bytes to make the structs (and potentially individual members) word-aligned for performance. – Kevin May 24 '12 at 14:55
  • 1
    To align to the required alignment of the contained types, yes. To align to excess alignment for no apparent reason? That's very odd... – R.. GitHub STOP HELPING ICE May 24 '12 at 16:35
  • The padding is to cause each element of an array of s1 structs to begin on a word boundary. Without doing so, some/all of the contained types would be misaligned. This is not odd at all and virtually every compiler does it. – Carey Gregory May 24 '12 at 17:09
  • 1
    @Kevin I believe R..'s concern is that the *fields* of the struct must be aligned to multiples of their size, but the struct itself might not live on an 8-byte boundary. Consider a struct with 2 4-byte fields. As long as the struct itself is on a 4 byte boundary, then so are both of its fields. Accessing either of these fields is guaranteed to not cause a read across multiple cache lines. But if different compilers are allowed to align the whole struct differently, then you'll run into trouble when trying to link things together. – Chris Rice May 24 '12 at 17:14
1

What is happening is structure padding.

It is done by the compiler to ensure that elements reside at aligned memory addresses.

You can read more about 'alignment' in x86/x86_64 here.

Now, why should they be at aligned addresses? (using 4 byte WORD as example): Machines access data from memory in 'words'. For a 4 byte WORD, this means that to read a single byte from the address b11001110, you will need to read 4 bytes (the last 2 bits in the address are basically, ignored while doing the read), then pick the byte you need once the WORD is in the CPU:

| b11001100 | b11001101 | b11001110 | b11001111 |    <- all four loaded at once
                        \           /
                        only one used

When you start reading bigger data types, then reading an 'unaligned' datum can cost more than reading an aligned one:

If you wanted to read 4 bytes (1 WORD) starting at the address b01110, instead of just one byte, then you would have to read 2 WORDS:

        first load             second load
/                       \/                      \
|01100|01101|01110|01111|10000|10001|10010|10011|
            \                       /
               unaligned data read

The compiler 'pads' structures in order to avoid such reads. Because they are costly. As Woodrow Douglass suggests in their answer, you can force the compiler to 'pack' instead of 'pad'.

One more thing: There are architectures where unaligned loads are not even possible. On such machines, the operating system usually catches exceptions raised during an unaligned load, and then simulates the load in some way (i.e. by doing multiple aligned loads, for example).

Community
  • 1
  • 1
ArjunShankar
  • 23,020
  • 5
  • 61
  • 83
-1

Is this a 64 bit machine? 72 bytes is a 64 bit word boundry. Your compiler is aligning your structure. In gcc, if you declare your structure with __attribute__((__packed__)), you can avoid this.

so declare your typedef like this:

typedef struct {
    ...
    ...
    struct s2;
} __attribute__((__packed__)) s1;
Woodrow Douglass
  • 2,605
  • 3
  • 25
  • 41
  • 1
    I don't think using `__packed__` is a good suggestion. Saving 4 bytes doesn't seem like a big deal, and unaligned memory accesses crash on some machines, and may be slow on others. – ugoren May 24 '12 at 14:31
  • I had made the assumption that if he noticed four bytes missing, then it matters; If his target is very embedded then this may be a big deal. If unaligned accesses crash, it's a compiler issue. If they're slow, you need to weigh speed against memory utilization. – Woodrow Douglass May 29 '12 at 13:02
  • @WoodrowDouglass - Like you said, gcc provides this specifically for cases where the programmer wants to use the minimum memory possible for a non-primitive data type. I think this is worth mentioning in your answer. I think at least one of the answers to this question ought to mention packing. – ArjunShankar Jun 01 '12 at 14:14