0

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?

4
  • 3
    Why not ask the compiler - it'll tell you with the sizeof operator. Commented Aug 23, 2010 at 11:03
  • Why do you want to know? Memory use? struct layout compatibility? pointer access to the structure? Commented Aug 23, 2010 at 11:04
  • You already know this is implementation defined. So asking these questions is silly. None of your assumptions can be held to be valid in all situations they are just that assumptions (somtimes they will be true others not). The compiler is free to add padding in any way it likes and may even change the padding with different flags. Commented Aug 23, 2010 at 14:45
  • Worry about field alignment and size issues when your profiler says this is the cause of the bottleneck and when you run out of memory in a closed system. Otherwise, focus on robustness and correctness. Commented Aug 23, 2010 at 18:01

6 Answers 6

4

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.

Sign up to request clarification or add additional context in comments.

13 Comments

It's not safe to assume at all ;)
Making any assumption about alignment is stupid. Do not do it. Even changing the compiler flags can cause the padding/alignment to change.
@Martin, if you do change the alignment or packing (which affects structure member alignment) you must know what you are doing, since your code won't be able to call standard C library and POSIX functions.
@Maxim: Avoiding POSIX for the moment. Even changing from release to debug could change the packing. A lot of systems provide two seprate runtimes one for debug one for release. Thus allowing for the potential for different packing/alignment between the two different versions. Not to mention systems that don't have a real runtime :-) There is no requirement for a compiler to have the same characteristics when different flags are used. This is why build systems tend to build all files with the same flags and debug/release binaries are built into seprate directories so they are not combined.
@Martin. I am not aware of any of the systems where debug and release builds have different alignment. Debug builds have optimizations off, extra run-time checks and debug symbols on and that is all the difference. Moreover, having different alignments leads to bugs not discovered in debug build, so it defeats the purpose of debug builds. Could you provide an example of a system/platform where debug and release builds have different alignment and why.
|
1

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.

Comments

1

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.

Comments

1

$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.

Comments

0

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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.