11

Imagine a struct made up of 32-bit, 16-bit, and 8-bit member values. Where the ordering of member values is such that each member is on it's natural boundary.

struct Foo
{
    uint32_t a;
    uint16_t b;
    uint8_t c;
    uint8_t d;
    uint32_t e;
};

Member alignment and padding rules are documented for Visual C++. sizeof(Foo) on VC++ the above struct is predictably "12".

Now, I'm pretty sure the rule is that no assumption should be made about padding and alignment, but in practice, do other compilers on other operating systems make similar guarantees?

If not, is there an equivalent of "#pragma pack(1)" on GCC?

selbie
  • 100,020
  • 15
  • 103
  • 173
  • In C, `Foo`, in `sizeof(Foo)`, is not declared. The expression is an error (unless `Foo` is defined/declared somewhere else). I suggest you do not try to write multi-language source files: the cons are much bigger than any pro you might find. – pmg Jun 05 '11 at 09:28
  • @pmg: Pedantry. :) `typedef struct Foo{ ... }Foo;` – Xeo Jun 05 '11 at 09:33
  • I believe the `typedef` is redundant (and therefore a safely removable source of bugs) in C++. My point remains: writing multi-language source files is more trouble than it's worth. – pmg Jun 05 '11 at 09:41

3 Answers3

8

In practice, on any system where the uintXX_t types exist, you will get the desired alignment with no padding. Don't throw in ugly gcc-isms to try to guarantee it.

Edit: To elaborate on why it may be harmful to use attribute packed or aligned, it may cause the whole struct to be misaligned when used as a member of a larger struct or on the stack. This will definitely hurt performance and, on non-x86 machines, will generate much larger code. It also means it's invalid to take a pointer to any member of the struct, since code that accesses the value through a pointer will not be aware that it could be misaligned and thus could fault.

As for why it's unnecessary, keep in mind that attribute is specific to gcc and gcc-workalike compilers. The C standard does not leave alignment undefined or unspecified. It's implementation-defined which means the implementation is required to further specify and document how it behaves. gcc's behavior is, and always has been, to align each struct member on the next boundary of its natural alignment (the same alignment it would have when used outside of a struct, which is necessarily a number that evenly divides the size of the type). Since attribute is a gcc feature, if you use it you're already assuming a gcc-like compiler, but then by assumption you have the alignment you want already.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
7

In general you are correct that it's not a safe assumption, although you will often get the packing you expect on many systems. You may want to use the packed attribute on your types when you use gcc.

E.g.

struct __attribute__((packed)) Blah { /* ... */ };
CB Bailey
  • 755,051
  • 104
  • 632
  • 656
6

On systems that actually offer those types, it is highly likely to work. On, say, a 36-bit system those types would not be available in the first place.

GCC provides an attribute
 

__attribute__ ((packed))

With similar effect.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • It is not really type dependent, but rather architecture dependent. For example some 16 or 32 bit processors cannot directly address an 8 bit address, so without padding may have to generate additional shift and mask instructions to extract an 8 bit value from a 16 or 32 bit memory read. This situation is far more common that your hypothetical 36 bit system (ARM7 for example). – Clifford Jun 05 '11 at 10:16
  • @Clifford: It's not common. The compiler already has to generate code for addressing an 8-bit type if it exists (because it can never be aligned in arrays), so it's no additional restraint. In general, "the alignment" of a type can never be larger than its size (and must divide its size), so it would be pathological for a compiler to impose larger alignment when the type is used in a struct. – R.. GitHub STOP HELPING ICE Jun 05 '11 at 11:16
  • I was not saying that the compiler could not or would not generate code for 8 bit accesses when necessary, rather for performance reasons it would avoid it for a struct. An array is guaranteed to be contiguous, a struct is not. I would suggest that ARM7 is common enough, but since this is tagged Linux, not so much in this context. – Clifford Jun 06 '11 at 19:46