John
John

Reputation: 3318

Structures in C

I got a structure like this:

struct bar {
    char x;
    char *y;
};

I can assume that on a 32 bit system, that padding for char will make it 4 bytes total, and a pointer in 32 bit is 4, so the total size will be 8 right?

I know it's all implementation specific, but I think if it's within 1-4, it should be padded to 4, within 5-8 to 8 and 9-16 within 16, is this right? it seems to work.

Would I be right to say that the struct will be 12 bytes in a x64 arch, because pointers are 8 bytes? Or what do you think it should be?

Upvotes: 0

Views: 363

Answers (6)

the_mandrill
the_mandrill

Reputation: 30842

As others have mentioned, the behaviour can't be relied upon between platforms. However, if you still need to do this, then one thing you can use is BOOST_STATIC_ASSERT() to ensure that if the assumptions are violated then you find out at compile time, eg

#include <boost/static_assert.hpp>
#if ARCH==x86                             // or whatever the platform specific #define is
  BOOST_STATIC_ASSERT(sizeof(bar)==8);
#elif ARCH==x64
  BOOST_STATIC_ASSERT(sizeof(bar)==16);
#else ...

If alignof() is available you could also use that to test your assumption.

Upvotes: 0

Maxim Egorushkin
Maxim Egorushkin

Reputation: 136256

Not quite.

Padding depends on the alignment requirement of the next member. The natural alignment of built-in data types is their size.

There is no padding before char members since their alignment requirement is 1 (assuming char is 1 byte).

For example, if a char (again assume it is one byte) is followed by a short, which, say, is 2 bytes, there may be up to 1 byte of padding because a short must be 2-byte aligned. If a char is followed by double of the size of 8, there may be up to 7 bytes of padding because a double is 8-byte aligned. On the other hand, if a short is followed by a double, the may be up to 6 bytes of padding.

And the size of a structure is a multiple of the alignment of a member with the largest alignment requirement, so there may be tail padding. In the following structure, for instance,

struct baz {
    double d;
    char c;
};

the member with the largest alignment requirement is d, it's alignment requirement is 8, Which gives sizeof(baz) == 2 * alignof(double). There is 7 bytes of tail padding after member c.

gcc and other modern compilers support __alignof() operator. There is also a portable version in boost.

Upvotes: 0

Chubsdad
Chubsdad

Reputation: 25497

$9.2/12-

Nonstatic data members of a (non-union) class declared without an intervening access-specifier are allocated so that later members have higher addresses within a class object. The order of allocation of nonstatic data members separated by an access-specifier is unspecified (11.1). Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).

So, it is highly implementation specific as you already mentioned.

Upvotes: 1

Potatoswatter
Potatoswatter

Reputation: 137810

You can't assume anything in general. Every platform decides its own padding rules.

That said, any architecture that uses "natural" alignment, where operands are padded to their own size (necessary and sufficient to avoid straddling naturally-aligned pages, cachelines, etc), will make bar twice the pointer size.

So, given natural alignment rules and nothing more, 8 bytes on 32-bit, 16 bytes on 64-bit.

Upvotes: 1

Chris Schmich
Chris Schmich

Reputation: 29476

I can assume that on a 32 bit system, that padding for char will make it 4 bytes total, and a pointer in 32 bit is 4, so the total size will be 8 right?

It's not safe to assume that, but that will often be the case, yes. For x86, fields are usually 32-bit aligned. The reason for this is to increase the system's performance at the cost of memory usage (see here).

Would I be right to say that the struct will be 12 bytes in a x64 arch, because pointers are 8 bytes? Or what do you think it should be?

Similarly, for x64, fields are usually 64-bit/8-byte aligned, so sizeof(bar) would be 16.

As Anders points out, however, all this goes flying out the window once you start playing with alignment via /Zp, the pack directive, or whatever else your compiler supports.

Upvotes: 4

AndersK
AndersK

Reputation: 36082

Its a compiler switch, you can't assume anything. If you assume you may get into trouble.

For instance in Visual Studio you can decide using pragma pack(1) that you want it directly on the byte boundary.

Upvotes: 1

Related Questions