为什么structof sizeof不等于每个成员的sizeof总和?

时间:2023-02-07 11:29:47

Why does the sizeof operator return a size larger for a structure than the total sizes of the structure's members?

为什么sizeof运算符返回的结构大小大于结构成员的总大小?

11 个解决方案

#1


554  

This is because of padding added to satisfy alignment constraints. Data structure alignment impacts both performance and correctness of programs:

这是因为添加了填充以满足对齐约束。数据结构对齐会影响程序的性能和正确性:

  • Mis-aligned access might be a hard error (often SIGBUS).
  • 错误对齐访问可能是一个硬错误(通常是SIGBUS)。

  • Mis-aligned access might be a soft error.
    • Either corrected in hardware, for a modest performance-degradation.
    • 在硬件中进行了更正,以适度降低性能。

    • Or corrected by emulation in software, for a severe performance-degradation.
    • 或者通过软件仿真进行校正,以避免严重的性能下降。

    • In addition, atomicity and other concurrency-guarantees might be broken, leading to subtle errors.
    • 此外,原子性和其他并发保证可能会被破坏,从而导致细微的错误。

  • 错误对齐的访问可能是软错误。在硬件中进行了更正,以适度降低性能。或者通过软件仿真进行校正,以避免严重的性能下降。此外,原子性和其他并发保证可能会被破坏,从而导致细微的错误。

Here's an example using typical settings for an x86 processor (all used 32 and 64 bit modes):

以下是使用x86处理器的典型设置(所有使用的32位和64位模式)的示例:

struct X{    short s; /* 2 bytes */             /* 2 padding bytes */    int   i; /* 4 bytes */    char  c; /* 1 byte */             /* 3 padding bytes */};struct Y{    int   i; /* 4 bytes */    char  c; /* 1 byte */             /* 1 padding byte */    short s; /* 2 bytes */};struct Z{    int   i; /* 4 bytes */    short s; /* 2 bytes */    char  c; /* 1 byte */             /* 1 padding byte */};const int sizeX = sizeof(struct X); /* = 12 */const int sizeY = sizeof(struct Y); /* = 8 */const int sizeZ = sizeof(struct Z); /* = 8 */

One can minimize the size of structures by sorting members by alignment (sorting by size suffices for that in basic types) (like structure Z in the example above).

可以通过对齐对成员进行排序来最小化结构的大小(按基本类型的大小排序就足够了)(如上例中的结构Z)。

IMPORTANT NOTE: Both the C and C++ standards state that structure alignment is implementation-defined. Therefore each compiler may choose to align data differently, resulting in different and incompatible data layouts. For this reason, when dealing with libraries that will be used by different compilers, it is important to understand how the compilers align data. Some compilers have command-line settings and/or special #pragma statements to change the structure alignment settings.

重要说明:C和C ++标准都声明结构对齐是实现定义的。因此,每个编译器可能选择以不同方式对齐数据,从而导致不同且不兼容的数据布局。因此,在处理将由不同编译器使用的库时,了解编译器如何对齐数据非常重要。某些编译器具有命令行设置和/或特殊的#pragma语句来更改结构对齐设置。

#2


148  

Packing and byte alignment, as described in the C FAQ here:

打包和字节对齐,如C FAQ中所述:

It's for alignment. Many processors can't access 2- and 4-byte quantities (e.g. ints and long ints) if they're crammed in every-which-way.

这是为了对齐。许多处理器如果以各种方式填充,则无法访问2字节和4字节数量(例如,整数和长整数)。

Suppose you have this structure:

假设你有这个结构:

struct {    char a[3];    short int b;    long int c;    char d[3];};

Now, you might think that it ought to be possible to pack this structure into memory like this:

现在,您可能认为应该可以将此结构打包到内存中,如下所示:

+-------+-------+-------+-------+|           a           |   b   |+-------+-------+-------+-------+|   b   |           c           |+-------+-------+-------+-------+|   c   |           d           |+-------+-------+-------+-------+

But it's much, much easier on the processor if the compiler arranges it like this:

但是如果编译器像这样安排它,它在处理器上要容易得多:

+-------+-------+-------+|           a           |+-------+-------+-------+|       b       |+-------+-------+-------+-------+|               c               |+-------+-------+-------+-------+|           d           |+-------+-------+-------+

In the packed version, notice how it's at least a little bit hard for you and me to see how the b and c fields wrap around? In a nutshell, it's hard for the processor, too. Therefore, most compilers will pad the structure (as if with extra, invisible fields) like this:

在打包版本中,请注意你和我看到b和c字段如何环绕至少有点困难?简而言之,处理器也很难。因此,大多数编译器将填充结构(就好像有额外的,不可见的字段),如下所示:

+-------+-------+-------+-------+|           a           | pad1  |+-------+-------+-------+-------+|       b       |     pad2      |+-------+-------+-------+-------+|               c               |+-------+-------+-------+-------+|           d           | pad3  |+-------+-------+-------+-------+

#3


23  

If you want the structure to have a certain size with GCC for example use __attribute__((packed)).

如果您希望结构具有GCC的特定大小,例如使用__attribute __((packed))。

On Windows you can set the alignment to one byte when using the cl.exe compier with the /Zp option.

在Windows上,使用带有/ Zp选项的cl.exe compier时,可以将对齐设置为一个字节。

Usually it is easier for the CPU to access data that is a multiple of 4 (or 8), depending platform and also on the compiler.

通常,CPU更容易访问4(或8)的倍数,具体取决于平台和编译器。

So it is a matter of alignment basically.

所以这基本上是一个对齐的问题。

You need to have good reasons to change it.

你需要有充分的理由去改变它。

#4


11  

This can be due to byte alignment and padding so that the structure comes out to an even number of bytes (or words) on your platform. For example in C on Linux, the following 3 structures:

这可能是由于字节对齐和填充,因此结构在平台上出现偶数个字节(或单词)。例如在Linux上的C语言中,有以下3种结构:

#include "stdio.h"struct oneInt {  int x;};struct twoInts {  int x;  int y;};struct someBits {  int x:2;  int y:6;};int main (int argc, char** argv) {  printf("oneInt=%zu\n",sizeof(struct oneInt));  printf("twoInts=%zu\n",sizeof(struct twoInts));  printf("someBits=%zu\n",sizeof(struct someBits));  return 0;}

Have members who's sizes (in bytes) are 4 bytes (32 bits), 8 bytes (2x 32 bits) and 1 byte (2+6 bits) respectively. The above program (on Linux using gcc) prints the sizes as 4, 8, and 4 - where the last structure is padded so that it is a single word (4 x 8 bit bytes on my 32bit platform).

具有大小(以字节为单位)的成员分别是4字节(32位),8字节(2x 32位)和1字节(2 + 6位)。上面的程序(在Linux上使用gcc)将大小打印为4,8和4 - 其中最后一个结构被填充,因此它是一个单词(在我的32位平台上为4 x 8位字节)。

oneInt=4twoInts=8someBits=4

#5


9  

See also:

for Microsoft Visual C:

对于Microsoft Visual C:

http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx

and GCC claim compatibility with Microsoft's compiler.:

和GCC声称与微软的编译器兼容:

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html

In addition to the previous answers, please note that regardless the packaging, there is no members-order-guarantee in C++. Compilers may (and certainly do) add virtual table pointer and base structures' members to the structure. Even the existence of virtual table is not ensured by the standard (virtual mechanism implementation is not specified) and therefore one can conclude that such guarantee is just impossible.

除了之前的答案,请注意,无论包装如何,C ++中都没有成员订单保证。编译器可以(当然也可以)将虚拟表指针和基础结构的成员添加到结构中。标准不能确保虚拟表的存在(未指定虚拟机制实现),因此可以得出结论,这种保证是不可能的。

I'm quite sure member-order is guaranteed in C, but I wouldn't count on it, when writing a cross-platform or cross-compiler program.

我很确定在C中保证成员顺序,但在编写跨平台或交叉编译程序时我不会指望它。

#6


6  

The size of a structure is greater than the sum of its parts because of what is called packing. A particular processor has a preferred data size that it works with. Most modern processors' preferred size if 32-bits (4 bytes). Accessing the memory when data is on this kind of boundary is more efficient than things that straddle that size boundary.

由于所谓的包装,结构的尺寸大于其部件的总和。特定处理器具有与其一起使用的优选数据大小。大多数现代处理器的首选大小,如果是32位(4字节)。当数据在这种边界上时访问存储器比跨越该大小边界的事物更有效。

For example. Consider the simple structure:

例如。考虑一下简单的结构:

struct myStruct{   int a;   char b;   int c;} data;

If the machine is a 32-bit machine and data is aligned on a 32-bit boundary, we see an immediate problem (assuming no structure alignment). In this example, let us assume that the structure data starts at address 1024 (0x400 - note that the lowest 2 bits are zero, so the data is aligned to a 32-bit boundary). The access to data.a will work fine because it starts on a boundary - 0x400. The access to data.b will also work fine, because it is at address 0x404 - another 32-bit boundary. But an unaligned structure would put data.c at address 0x405. The 4 bytes of data.c are at 0x405, 0x406, 0x407, 0x408. On a 32-bit machine, the system would read data.c during one memory cycle, but would only get 3 of the 4 bytes (the 4th byte is on the next boundary). So, the system would have to do a second memory access to get the 4th byte,

如果机器是32位机器并且数据在32位边界上对齐,我们会立即看到问题(假设没有结构对齐)。在这个例子中,让我们假设结构数据从地址1024开始(0x400 - 注意最低的2位为零,因此数据与32位边界对齐)。对data.a的访问将正常工作,因为它从边界开始 - 0x400。对data.b的访问也可以正常工作,因为它位于地址0x404 - 另一个32位边界。但是未对齐的结构会将data.c放在地址0x405处。 data.c的4个字节位于0x405,0x406,0x407,0x408。在32位机器上,系统将在一个存储器周期内读取data.c,但只能获得4个字节中的3个(第4个字节位于下一个边界)。因此,系统必须进行第二次内存访问才能获得第4个字节,

Now, if instead of putting data.c at address 0x405, the compiler padded the structure by 3 bytes and put data.c at address 0x408, then the system would only need 1 cycle to read the data, cutting access time to that data element by 50%. Padding swaps memory efficiency for processing efficiency. Given that computers can have huge amounts of memory (many gigabytes), the compilers feel that the swap (speed over size) is a reasonable one.

现在,如果不是将data.c放在地址0x405,编译器将结构填充3个字节并将data.c放在地址0x408,那么系统只需要1个周期来读取数据,从而缩短了对该数据元素的访问时间减少50%。填充交换内存效率以提高处理效率。鉴于计算机可以拥有大量内存(许多千兆字节),编译器认为交换(速度超过大小)是合理的。

Unfortunately, this problem becomes a killer when you attempt to send structures over a network or even write the binary data to a binary file. The padding inserted between elements of a structure or class can disrupt the data sent to the file or network. In order to write portable code (one that will go to several different compilers), you will probably have to access each element of the structure separately to ensure the proper "packing".

不幸的是,当您尝试通过网络发送结构甚至将二进制数据写入二进制文件时,此问题将成为杀手。在结构或类的元素之间插入的填充可以破坏发送到文件或网络的数据。为了编写可移植代码(一个将转到几个不同的编译器),您可能必须分别访问结构的每个元素以确保正确的“打包”。

On the other hand, different compilers have different abilities to manage data structure packing. For example, in Visual C/C++ the compiler supports the #pragma pack command. This will allow you to adjust data packing and alignment.

另一方面,不同的编译器具有不同的管理数据结构打包的能力。例如,在Visual C / C ++中,编译器支持#pragma pack命令。这将允许您调整数据打包和对齐。

For example:

#pragma pack 1struct MyStruct{    int a;    char b;    int c;    short d;} myData;I = sizeof(myData);

I should now have the length of 11. Without the pragma, I could be anything from 11 to 14 (and for some systems, as much as 32), depending on the default packing of the compiler.

我现在应该有11的长度。没有编译指示,我可以是11到14之间的任何东西(对于某些系统,多达32个),具体取决于编译器的默认打包。

#7


5  

It can do so if you have implicitly or explicitly set the alignment of the struct. A struct that is aligned 4 will always be a multiple of 4 bytes even if the size of its members would be something that's not a multiple of 4 bytes.

如果您隐式或显式设置结构的对齐方式,它可以这样做。对齐4的结构将始终是4个字节的倍数,即使其成员的大小不是4个字节的倍数。

Also a library may be compiled under x86 with 32-bit ints and you may be comparing its components on a 64-bit process would would give you a different result if you were doing this by hand.

也可以在x86下使用32位整数编译库,如果您手动执行此操作,您可能会在64位进程上比较其组件会产生不同的结果。

#8


5  

C99 N1256 standard draft

C99 N1256标准草案

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

6.5.3.4 The sizeof operator:

6.5.3.4 sizeof运算符:

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.

3当应用于具有结构或联合类型的操作数时,结果是此类对象中的总字节数,包括内部和尾部填充。

6.7.2.1 Structure and union specifiers:

6.7.2.1结构和联合说明符:

13 ... There may be unnamed padding within a structure object, but not at its beginning.

13 ...结构对象中可能有未命名的填充,但不是在它的开头。

and:

15 There may be unnamed padding at the end of a structure or union.

15结构或联合的末尾可能有未命名的填充。

The new C99 flexible array member feature (struct S {int is[];};) may also affect padding:

新的C99灵活数组成员功能(struct S {int is [];};)也可能影响填充:

16 As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply.

16作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这称为灵活的阵列成员。在大多数情况下,忽略灵活的数组成员。特别地,结构的尺寸好像省略了柔性阵列构件,除了它可以具有比遗漏所暗示的更多的拖尾填充。

Annex J Portability Issues reiterates:

附件J可携带性问题重申:

The following are unspecified: ...

以下是未指定的:......

  • The value of padding bytes when storing values in structures or unions (6.2.6.1)
  • 在结构或联合中存储值时填充字节的值(6.2.6.1)

C++11 N3337 standard draft

C ++ 11 N3337标准草案

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

5.3.3 Sizeof:

2 When applied to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array.

2应用于类时,结果是该类对象中的字节数,包括在数组中放置该类型对象所需的任何填充。

9.2 Class members:

9.2班级成员:

A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note ]

指向标准布局结构对象的指针(使用reinterpret_cast进行适当转换)指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。 [注意:因此,在标准布局结构对象中可能存在未命名的填充,但不是在其开头,以实现适当的对齐。 - 结束说明]

I only know enough C++ to understand the note :-)

我只知道足够的C ++来理解笔记:-)

#9


4  

In addition to the other answers, a struct can (but usually doesn't) have virtual functions, in which case the size of the struct will also include the space for the vtbl.

除了其他答案之外,结构可以(但通常不)具有虚函数,在这种情况下,结构的大小也将包括vtbl的空间。

#10


3  

C language leaves compiler some freedom about the location of the structural elements in the memory:

C语言为编译器留下了关于内存中结构元素位置的一些*:

  • memory holes may appear between any two components, and after the last component. It was due to the fact that certain types of objects on the target computer may be limited by the boundaries of addressing
  • 内存孔可能出现在任何两个组件之间,以及最后一个组件之后。这是因为目标计算机上的某些类型的对象可能受到寻址边界的限制

  • "memory holes" size included in the result of sizeof operator. The sizeof only doesn't include size of the flexible array, which is available in C/C++
  • sizeof运算符的结果中包含“memory hole”大小。 sizeof仅包括灵活数组的大小,可在C / C ++中使用

  • Some implementations of the language allow you to control the memory layout of structures through the pragma and compiler options
  • 该语言的某些实现允许您通过编译指示和编译器选项控制结构的内存布局

The C language provides some assurance to the programmer of the elements layout in the structure:

C语言为程序员提供了结构中元素布局的一些保证:

  • compilers required to assign a sequence of components increasing memory addresses
  • 编译器需要分配一系列增加内存地址的组件

  • Address of the first component coincides with the start address of the structure
  • 第一个组件的地址与结构的起始地址一致

  • unnamed bit fields may be included in the structure to the required address alignments of adjacent elements
  • 未命名的位字段可以包括在结构中,以包含相邻元素的所需地址对齐

Problems related to the elements alignment:

与元素对齐相关的问题:

  • Different computers line the edges of objects in different ways
  • 不同的计算机以不同的方式排列对象的边缘

  • Different restrictions on the width of the bit field
  • 对位域宽度的不同限制

  • Computers differ on how to store the bytes in a word (Intel 80x86 and Motorola 68000)
  • 计算机在如何存储单词中的字节方面存在差异(英特尔80x86和摩托罗拉68000)

How alignment works:

对齐如何工作:

  • The volume occupied by the structure is calculated as the size of the aligned single element of an array of such structures. The structure shouldend so that the first element of the next following structure does not the violate requirements of alignment
  • 结构占据的体积计算为这种结构阵列的对齐单个元素的大小。结构应该使下一个结构的第一个元素不违反对齐要求

p.s More detailed info are available here: "Samuel P.Harbison, Guy L.Steele C A Reference, (5.6.2 - 5.6.7)"

p.s更多详细信息请点击此处:“Samuel P.Harbison,Guy L.Steele C A Reference,(5.6.2 - 5.6.7)”

#11


2  

The idea is that for speed and cache considerations, operands should be read from addresses aligned to their natural size. To make this happen, the compiler pads structure members so the following member or following struct will be aligned.

我们的想法是,对于速度和缓存考虑因素,操作数应该从与其自然大小对齐的地址中读取。为了实现这一点,编译器将填充结构成员,以便对齐以下成员或后续结构。

struct pixel {    unsigned char red;   // 0    unsigned char green; // 1    unsigned int alpha;  // 4 (gotta skip to an aligned offset)    unsigned char blue;  // 8 (then skip 9 10 11)};// next offset: 12

The x86 architecture has always been able to fetch misaligned addresses. However, it's slower and when the misalignment overlaps two different cache lines, then it evicts two cache lines when an aligned access would only evict one.

x86架构始终能够获取未对齐的地址。然而,它更慢并且当未对准与两个不同的高速缓存行重叠时,当对齐的访问仅驱逐一个时,它将驱逐两个高速缓存行。

Some architectures actually have to trap on misaligned reads and writes, and early versions of the ARM architecture (the one that evolved into all of today's mobile CPUs) ... well, they actually just returned bad data on for those. (They ignored the low-order bits.)

有些架构实际上必须捕获未对齐的读写,以及ARM架构的早期版本(演变成当今所有移动CPU的版本)......好吧,它们实际上只是返回了不良数据。 (他们忽略了低位。)

Finally, note that cache lines can be arbitrarily large, and the compiler doesn't attempt to guess at those or make a space-vs-speed tradeoff. Instead, the alignment decisions are part of the ABI and represent the minimum alignment that will eventually evenly fill up a cache line.

最后,请注意,缓存行可以任意大,并且编译器不会尝试猜测那些缓存行或进行空间与速度的权衡。相反,对齐决策是ABI的一部分,表示最终将均匀填充缓存行的最小对齐。

TL;DR: alignment is important.

TL; DR:对齐非常重要。

#1


554  

This is because of padding added to satisfy alignment constraints. Data structure alignment impacts both performance and correctness of programs:

这是因为添加了填充以满足对齐约束。数据结构对齐会影响程序的性能和正确性:

  • Mis-aligned access might be a hard error (often SIGBUS).
  • 错误对齐访问可能是一个硬错误(通常是SIGBUS)。

  • Mis-aligned access might be a soft error.
    • Either corrected in hardware, for a modest performance-degradation.
    • 在硬件中进行了更正,以适度降低性能。

    • Or corrected by emulation in software, for a severe performance-degradation.
    • 或者通过软件仿真进行校正,以避免严重的性能下降。

    • In addition, atomicity and other concurrency-guarantees might be broken, leading to subtle errors.
    • 此外,原子性和其他并发保证可能会被破坏,从而导致细微的错误。

  • 错误对齐的访问可能是软错误。在硬件中进行了更正,以适度降低性能。或者通过软件仿真进行校正,以避免严重的性能下降。此外,原子性和其他并发保证可能会被破坏,从而导致细微的错误。

Here's an example using typical settings for an x86 processor (all used 32 and 64 bit modes):

以下是使用x86处理器的典型设置(所有使用的32位和64位模式)的示例:

struct X{    short s; /* 2 bytes */             /* 2 padding bytes */    int   i; /* 4 bytes */    char  c; /* 1 byte */             /* 3 padding bytes */};struct Y{    int   i; /* 4 bytes */    char  c; /* 1 byte */             /* 1 padding byte */    short s; /* 2 bytes */};struct Z{    int   i; /* 4 bytes */    short s; /* 2 bytes */    char  c; /* 1 byte */             /* 1 padding byte */};const int sizeX = sizeof(struct X); /* = 12 */const int sizeY = sizeof(struct Y); /* = 8 */const int sizeZ = sizeof(struct Z); /* = 8 */

One can minimize the size of structures by sorting members by alignment (sorting by size suffices for that in basic types) (like structure Z in the example above).

可以通过对齐对成员进行排序来最小化结构的大小(按基本类型的大小排序就足够了)(如上例中的结构Z)。

IMPORTANT NOTE: Both the C and C++ standards state that structure alignment is implementation-defined. Therefore each compiler may choose to align data differently, resulting in different and incompatible data layouts. For this reason, when dealing with libraries that will be used by different compilers, it is important to understand how the compilers align data. Some compilers have command-line settings and/or special #pragma statements to change the structure alignment settings.

重要说明:C和C ++标准都声明结构对齐是实现定义的。因此,每个编译器可能选择以不同方式对齐数据,从而导致不同且不兼容的数据布局。因此,在处理将由不同编译器使用的库时,了解编译器如何对齐数据非常重要。某些编译器具有命令行设置和/或特殊的#pragma语句来更改结构对齐设置。

#2


148  

Packing and byte alignment, as described in the C FAQ here:

打包和字节对齐,如C FAQ中所述:

It's for alignment. Many processors can't access 2- and 4-byte quantities (e.g. ints and long ints) if they're crammed in every-which-way.

这是为了对齐。许多处理器如果以各种方式填充,则无法访问2字节和4字节数量(例如,整数和长整数)。

Suppose you have this structure:

假设你有这个结构:

struct {    char a[3];    short int b;    long int c;    char d[3];};

Now, you might think that it ought to be possible to pack this structure into memory like this:

现在,您可能认为应该可以将此结构打包到内存中,如下所示:

+-------+-------+-------+-------+|           a           |   b   |+-------+-------+-------+-------+|   b   |           c           |+-------+-------+-------+-------+|   c   |           d           |+-------+-------+-------+-------+

But it's much, much easier on the processor if the compiler arranges it like this:

但是如果编译器像这样安排它,它在处理器上要容易得多:

+-------+-------+-------+|           a           |+-------+-------+-------+|       b       |+-------+-------+-------+-------+|               c               |+-------+-------+-------+-------+|           d           |+-------+-------+-------+

In the packed version, notice how it's at least a little bit hard for you and me to see how the b and c fields wrap around? In a nutshell, it's hard for the processor, too. Therefore, most compilers will pad the structure (as if with extra, invisible fields) like this:

在打包版本中,请注意你和我看到b和c字段如何环绕至少有点困难?简而言之,处理器也很难。因此,大多数编译器将填充结构(就好像有额外的,不可见的字段),如下所示:

+-------+-------+-------+-------+|           a           | pad1  |+-------+-------+-------+-------+|       b       |     pad2      |+-------+-------+-------+-------+|               c               |+-------+-------+-------+-------+|           d           | pad3  |+-------+-------+-------+-------+

#3


23  

If you want the structure to have a certain size with GCC for example use __attribute__((packed)).

如果您希望结构具有GCC的特定大小,例如使用__attribute __((packed))。

On Windows you can set the alignment to one byte when using the cl.exe compier with the /Zp option.

在Windows上,使用带有/ Zp选项的cl.exe compier时,可以将对齐设置为一个字节。

Usually it is easier for the CPU to access data that is a multiple of 4 (or 8), depending platform and also on the compiler.

通常,CPU更容易访问4(或8)的倍数,具体取决于平台和编译器。

So it is a matter of alignment basically.

所以这基本上是一个对齐的问题。

You need to have good reasons to change it.

你需要有充分的理由去改变它。

#4


11  

This can be due to byte alignment and padding so that the structure comes out to an even number of bytes (or words) on your platform. For example in C on Linux, the following 3 structures:

这可能是由于字节对齐和填充,因此结构在平台上出现偶数个字节(或单词)。例如在Linux上的C语言中,有以下3种结构:

#include "stdio.h"struct oneInt {  int x;};struct twoInts {  int x;  int y;};struct someBits {  int x:2;  int y:6;};int main (int argc, char** argv) {  printf("oneInt=%zu\n",sizeof(struct oneInt));  printf("twoInts=%zu\n",sizeof(struct twoInts));  printf("someBits=%zu\n",sizeof(struct someBits));  return 0;}

Have members who's sizes (in bytes) are 4 bytes (32 bits), 8 bytes (2x 32 bits) and 1 byte (2+6 bits) respectively. The above program (on Linux using gcc) prints the sizes as 4, 8, and 4 - where the last structure is padded so that it is a single word (4 x 8 bit bytes on my 32bit platform).

具有大小(以字节为单位)的成员分别是4字节(32位),8字节(2x 32位)和1字节(2 + 6位)。上面的程序(在Linux上使用gcc)将大小打印为4,8和4 - 其中最后一个结构被填充,因此它是一个单词(在我的32位平台上为4 x 8位字节)。

oneInt=4twoInts=8someBits=4

#5


9  

See also:

for Microsoft Visual C:

对于Microsoft Visual C:

http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx

and GCC claim compatibility with Microsoft's compiler.:

和GCC声称与微软的编译器兼容:

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html

In addition to the previous answers, please note that regardless the packaging, there is no members-order-guarantee in C++. Compilers may (and certainly do) add virtual table pointer and base structures' members to the structure. Even the existence of virtual table is not ensured by the standard (virtual mechanism implementation is not specified) and therefore one can conclude that such guarantee is just impossible.

除了之前的答案,请注意,无论包装如何,C ++中都没有成员订单保证。编译器可以(当然也可以)将虚拟表指针和基础结构的成员添加到结构中。标准不能确保虚拟表的存在(未指定虚拟机制实现),因此可以得出结论,这种保证是不可能的。

I'm quite sure member-order is guaranteed in C, but I wouldn't count on it, when writing a cross-platform or cross-compiler program.

我很确定在C中保证成员顺序,但在编写跨平台或交叉编译程序时我不会指望它。

#6


6  

The size of a structure is greater than the sum of its parts because of what is called packing. A particular processor has a preferred data size that it works with. Most modern processors' preferred size if 32-bits (4 bytes). Accessing the memory when data is on this kind of boundary is more efficient than things that straddle that size boundary.

由于所谓的包装,结构的尺寸大于其部件的总和。特定处理器具有与其一起使用的优选数据大小。大多数现代处理器的首选大小,如果是32位(4字节)。当数据在这种边界上时访问存储器比跨越该大小边界的事物更有效。

For example. Consider the simple structure:

例如。考虑一下简单的结构:

struct myStruct{   int a;   char b;   int c;} data;

If the machine is a 32-bit machine and data is aligned on a 32-bit boundary, we see an immediate problem (assuming no structure alignment). In this example, let us assume that the structure data starts at address 1024 (0x400 - note that the lowest 2 bits are zero, so the data is aligned to a 32-bit boundary). The access to data.a will work fine because it starts on a boundary - 0x400. The access to data.b will also work fine, because it is at address 0x404 - another 32-bit boundary. But an unaligned structure would put data.c at address 0x405. The 4 bytes of data.c are at 0x405, 0x406, 0x407, 0x408. On a 32-bit machine, the system would read data.c during one memory cycle, but would only get 3 of the 4 bytes (the 4th byte is on the next boundary). So, the system would have to do a second memory access to get the 4th byte,

如果机器是32位机器并且数据在32位边界上对齐,我们会立即看到问题(假设没有结构对齐)。在这个例子中,让我们假设结构数据从地址1024开始(0x400 - 注意最低的2位为零,因此数据与32位边界对齐)。对data.a的访问将正常工作,因为它从边界开始 - 0x400。对data.b的访问也可以正常工作,因为它位于地址0x404 - 另一个32位边界。但是未对齐的结构会将data.c放在地址0x405处。 data.c的4个字节位于0x405,0x406,0x407,0x408。在32位机器上,系统将在一个存储器周期内读取data.c,但只能获得4个字节中的3个(第4个字节位于下一个边界)。因此,系统必须进行第二次内存访问才能获得第4个字节,

Now, if instead of putting data.c at address 0x405, the compiler padded the structure by 3 bytes and put data.c at address 0x408, then the system would only need 1 cycle to read the data, cutting access time to that data element by 50%. Padding swaps memory efficiency for processing efficiency. Given that computers can have huge amounts of memory (many gigabytes), the compilers feel that the swap (speed over size) is a reasonable one.

现在,如果不是将data.c放在地址0x405,编译器将结构填充3个字节并将data.c放在地址0x408,那么系统只需要1个周期来读取数据,从而缩短了对该数据元素的访问时间减少50%。填充交换内存效率以提高处理效率。鉴于计算机可以拥有大量内存(许多千兆字节),编译器认为交换(速度超过大小)是合理的。

Unfortunately, this problem becomes a killer when you attempt to send structures over a network or even write the binary data to a binary file. The padding inserted between elements of a structure or class can disrupt the data sent to the file or network. In order to write portable code (one that will go to several different compilers), you will probably have to access each element of the structure separately to ensure the proper "packing".

不幸的是,当您尝试通过网络发送结构甚至将二进制数据写入二进制文件时,此问题将成为杀手。在结构或类的元素之间插入的填充可以破坏发送到文件或网络的数据。为了编写可移植代码(一个将转到几个不同的编译器),您可能必须分别访问结构的每个元素以确保正确的“打包”。

On the other hand, different compilers have different abilities to manage data structure packing. For example, in Visual C/C++ the compiler supports the #pragma pack command. This will allow you to adjust data packing and alignment.

另一方面,不同的编译器具有不同的管理数据结构打包的能力。例如,在Visual C / C ++中,编译器支持#pragma pack命令。这将允许您调整数据打包和对齐。

For example:

#pragma pack 1struct MyStruct{    int a;    char b;    int c;    short d;} myData;I = sizeof(myData);

I should now have the length of 11. Without the pragma, I could be anything from 11 to 14 (and for some systems, as much as 32), depending on the default packing of the compiler.

我现在应该有11的长度。没有编译指示,我可以是11到14之间的任何东西(对于某些系统,多达32个),具体取决于编译器的默认打包。

#7


5  

It can do so if you have implicitly or explicitly set the alignment of the struct. A struct that is aligned 4 will always be a multiple of 4 bytes even if the size of its members would be something that's not a multiple of 4 bytes.

如果您隐式或显式设置结构的对齐方式,它可以这样做。对齐4的结构将始终是4个字节的倍数,即使其成员的大小不是4个字节的倍数。

Also a library may be compiled under x86 with 32-bit ints and you may be comparing its components on a 64-bit process would would give you a different result if you were doing this by hand.

也可以在x86下使用32位整数编译库,如果您手动执行此操作,您可能会在64位进程上比较其组件会产生不同的结果。

#8


5  

C99 N1256 standard draft

C99 N1256标准草案

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

6.5.3.4 The sizeof operator:

6.5.3.4 sizeof运算符:

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.

3当应用于具有结构或联合类型的操作数时,结果是此类对象中的总字节数,包括内部和尾部填充。

6.7.2.1 Structure and union specifiers:

6.7.2.1结构和联合说明符:

13 ... There may be unnamed padding within a structure object, but not at its beginning.

13 ...结构对象中可能有未命名的填充,但不是在它的开头。

and:

15 There may be unnamed padding at the end of a structure or union.

15结构或联合的末尾可能有未命名的填充。

The new C99 flexible array member feature (struct S {int is[];};) may also affect padding:

新的C99灵活数组成员功能(struct S {int is [];};)也可能影响填充:

16 As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a flexible array member. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply.

16作为一种特殊情况,具有多个命名成员的结构的最后一个元素可能具有不完整的数组类型;这称为灵活的阵列成员。在大多数情况下,忽略灵活的数组成员。特别地,结构的尺寸好像省略了柔性阵列构件,除了它可以具有比遗漏所暗示的更多的拖尾填充。

Annex J Portability Issues reiterates:

附件J可携带性问题重申:

The following are unspecified: ...

以下是未指定的:......

  • The value of padding bytes when storing values in structures or unions (6.2.6.1)
  • 在结构或联合中存储值时填充字节的值(6.2.6.1)

C++11 N3337 standard draft

C ++ 11 N3337标准草案

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

5.3.3 Sizeof:

2 When applied to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array.

2应用于类时,结果是该类对象中的字节数,包括在数组中放置该类型对象所需的任何填充。

9.2 Class members:

9.2班级成员:

A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa. [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note ]

指向标准布局结构对象的指针(使用reinterpret_cast进行适当转换)指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。 [注意:因此,在标准布局结构对象中可能存在未命名的填充,但不是在其开头,以实现适当的对齐。 - 结束说明]

I only know enough C++ to understand the note :-)

我只知道足够的C ++来理解笔记:-)

#9


4  

In addition to the other answers, a struct can (but usually doesn't) have virtual functions, in which case the size of the struct will also include the space for the vtbl.

除了其他答案之外,结构可以(但通常不)具有虚函数,在这种情况下,结构的大小也将包括vtbl的空间。

#10


3  

C language leaves compiler some freedom about the location of the structural elements in the memory:

C语言为编译器留下了关于内存中结构元素位置的一些*:

  • memory holes may appear between any two components, and after the last component. It was due to the fact that certain types of objects on the target computer may be limited by the boundaries of addressing
  • 内存孔可能出现在任何两个组件之间,以及最后一个组件之后。这是因为目标计算机上的某些类型的对象可能受到寻址边界的限制

  • "memory holes" size included in the result of sizeof operator. The sizeof only doesn't include size of the flexible array, which is available in C/C++
  • sizeof运算符的结果中包含“memory hole”大小。 sizeof仅包括灵活数组的大小,可在C / C ++中使用

  • Some implementations of the language allow you to control the memory layout of structures through the pragma and compiler options
  • 该语言的某些实现允许您通过编译指示和编译器选项控制结构的内存布局

The C language provides some assurance to the programmer of the elements layout in the structure:

C语言为程序员提供了结构中元素布局的一些保证:

  • compilers required to assign a sequence of components increasing memory addresses
  • 编译器需要分配一系列增加内存地址的组件

  • Address of the first component coincides with the start address of the structure
  • 第一个组件的地址与结构的起始地址一致

  • unnamed bit fields may be included in the structure to the required address alignments of adjacent elements
  • 未命名的位字段可以包括在结构中,以包含相邻元素的所需地址对齐

Problems related to the elements alignment:

与元素对齐相关的问题:

  • Different computers line the edges of objects in different ways
  • 不同的计算机以不同的方式排列对象的边缘

  • Different restrictions on the width of the bit field
  • 对位域宽度的不同限制

  • Computers differ on how to store the bytes in a word (Intel 80x86 and Motorola 68000)
  • 计算机在如何存储单词中的字节方面存在差异(英特尔80x86和摩托罗拉68000)

How alignment works:

对齐如何工作:

  • The volume occupied by the structure is calculated as the size of the aligned single element of an array of such structures. The structure shouldend so that the first element of the next following structure does not the violate requirements of alignment
  • 结构占据的体积计算为这种结构阵列的对齐单个元素的大小。结构应该使下一个结构的第一个元素不违反对齐要求

p.s More detailed info are available here: "Samuel P.Harbison, Guy L.Steele C A Reference, (5.6.2 - 5.6.7)"

p.s更多详细信息请点击此处:“Samuel P.Harbison,Guy L.Steele C A Reference,(5.6.2 - 5.6.7)”

#11


2  

The idea is that for speed and cache considerations, operands should be read from addresses aligned to their natural size. To make this happen, the compiler pads structure members so the following member or following struct will be aligned.

我们的想法是,对于速度和缓存考虑因素,操作数应该从与其自然大小对齐的地址中读取。为了实现这一点,编译器将填充结构成员,以便对齐以下成员或后续结构。

struct pixel {    unsigned char red;   // 0    unsigned char green; // 1    unsigned int alpha;  // 4 (gotta skip to an aligned offset)    unsigned char blue;  // 8 (then skip 9 10 11)};// next offset: 12

The x86 architecture has always been able to fetch misaligned addresses. However, it's slower and when the misalignment overlaps two different cache lines, then it evicts two cache lines when an aligned access would only evict one.

x86架构始终能够获取未对齐的地址。然而,它更慢并且当未对准与两个不同的高速缓存行重叠时,当对齐的访问仅驱逐一个时,它将驱逐两个高速缓存行。

Some architectures actually have to trap on misaligned reads and writes, and early versions of the ARM architecture (the one that evolved into all of today's mobile CPUs) ... well, they actually just returned bad data on for those. (They ignored the low-order bits.)

有些架构实际上必须捕获未对齐的读写,以及ARM架构的早期版本(演变成当今所有移动CPU的版本)......好吧,它们实际上只是返回了不良数据。 (他们忽略了低位。)

Finally, note that cache lines can be arbitrarily large, and the compiler doesn't attempt to guess at those or make a space-vs-speed tradeoff. Instead, the alignment decisions are part of the ABI and represent the minimum alignment that will eventually evenly fill up a cache line.

最后,请注意,缓存行可以任意大,并且编译器不会尝试猜测那些缓存行或进行空间与速度的权衡。相反,对齐决策是ABI的一部分,表示最终将均匀填充缓存行的最小对齐。

TL;DR: alignment is important.

TL; DR:对齐非常重要。