Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/132.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么不是';结构的t sizeof等于每个成员的sizeof之和?_C++_C_Struct_Sizeof_C++ Faq - Fatal编程技术网

C++ 为什么不是';结构的t sizeof等于每个成员的sizeof之和?

C++ 为什么不是';结构的t sizeof等于每个成员的sizeof之和?,c++,c,struct,sizeof,c++-faq,C++,C,Struct,Sizeof,C++ Faq,为什么sizeof运算符返回的结构尺寸大于结构成员的总尺寸?这是因为添加了填充以满足对齐约束。影响程序的性能和正确性: 错误对齐的访问可能是一个硬错误(通常是SIGBUS) 错误对齐的访问可能是一个软错误。 这两种方法都在硬件上得到了纠正,性能略有下降 或通过软件仿真进行纠正,导致性能严重下降 此外,原子性和其他并发性保证可能会被破坏,从而导致微妙的错误 下面是一个使用x86处理器典型设置的示例(均使用32位和64位模式): 可以通过按对齐方式对成员进行排序(按大小排序足以满足基本类型中

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

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

  • 错误对齐的访问可能是一个硬错误(通常是
    SIGBUS
  • 错误对齐的访问可能是一个软错误。
    • 这两种方法都在硬件上得到了纠正,性能略有下降
    • 或通过软件仿真进行纠正,导致性能严重下降
    • 此外,原子性和其他并发性保证可能会被破坏,从而导致微妙的错误
下面是一个使用x86处理器典型设置的示例(均使用32位和64位模式):

可以通过按对齐方式对成员进行排序(按大小排序足以满足基本类型中的排序)(如上面示例中的结构
Z


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

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


此外,库可能在x86下编译,具有32位整数,您可能在64位进程上比较它的组件,如果您手动执行此操作,将得到不同的结果。

打包和字节对齐,如C常见问题解答中所述:

这是为了校准。许多处理器无法访问2字节和4字节 数量(例如整数和长整数),如果它们被塞满 四面八方

假设您有以下结构:

struct {
    char a[3];
    short int b;
    long int c;
    char d[3];
};
struct myStruct
{
   int a;
   char b;
   int c;
} data;
现在,你可能认为应该可以打包这个 将结构存储到内存中,如下所示:

+-------+-------+-------+-------+
|           a           |   b   |
+-------+-------+-------+-------+
|   b   |           c           |
+-------+-------+-------+-------+
|   c   |           d           |
+-------+-------+-------+-------+
+-------+-------+-------+
|           a           |
+-------+-------+-------+
|       b       |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           |
+-------+-------+-------+
+-------+-------+-------+-------+
|           a           | pad1  |
+-------+-------+-------+-------+
|       b       |     pad2      |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           | pad3  |
+-------+-------+-------+-------+
但是,如果编译器进行安排,那么在处理器上就容易多了 它是这样的:

+-------+-------+-------+-------+
|           a           |   b   |
+-------+-------+-------+-------+
|   b   |           c           |
+-------+-------+-------+-------+
|   c   |           d           |
+-------+-------+-------+-------+
+-------+-------+-------+
|           a           |
+-------+-------+-------+
|       b       |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           |
+-------+-------+-------+
+-------+-------+-------+-------+
|           a           | pad1  |
+-------+-------+-------+-------+
|       b       |     pad2      |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           | pad3  |
+-------+-------+-------+-------+
在打包的版本中,请注意,对于 你和我想看看b和c字段是如何缠绕的?简而言之 这对处理器来说也很难。因此,大多数编译器将使用pad 结构(好像有额外的不可见字段)如下所示:

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

这可能是由于字节对齐和填充,因此在您的平台上,结构的字节数(或单词数)为偶数。例如,在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;
}
成员的大小(以字节为单位)分别为4字节(32位)、8字节(2x32位)和1字节(2+6位)。上面的程序(在Linux上使用gcc)将大小打印为4、8和4,其中最后一个结构被填充为单个字(在我的32位平台上为4 x 8位字节)


例如,如果您希望使用GCC使结构具有一定的大小,请使用

在Windows上,使用cl.exe编译器时,可以将对齐设置为一个字节

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

因此,这基本上是一个对齐的问题


您需要有充分的理由来更改它。

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

另请参见:

对于Microsoft Visual C:

和GCC声明与Microsoft编译器兼容:

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


我很肯定成员顺序在C中是有保证的,但在编写跨平台或跨编译器程序时,我不会指望它。

由于所谓的打包,结构的大小大于其部分的总和。一个特定的处理器有一个它使用的首选数据大小。大多数现代处理器的首选大小为32位(4字节)。当数据位于这种边界上时访问内存比跨越这种大小边界的东西更有效

比如说。考虑简单的结构:

struct {
    char a[3];
    short int b;
    long int c;
    char d[3];
};
struct myStruct
{
   int a;
   char b;
   int c;
} data;
如果机器是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个字节

现在,如果编译器不将data.c放在地址0x405,而是将结构填充3个字节,并将data.c放在地址0x408,那么系统只需要