Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.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+的大小是多少+;班级决定? >强>摘要>强:编译器在编译时如何静态地确定C++类的大小?_C++_Memory Alignment - Fatal编程技术网

C+的大小是多少+;班级决定? >强>摘要>强:编译器在编译时如何静态地确定C++类的大小?

C+的大小是多少+;班级决定? >强>摘要>强:编译器在编译时如何静态地确定C++类的大小?,c++,memory-alignment,C++,Memory Alignment,详细信息: 我试图理解确定一个类将使用多少内存的规则是什么,以及内存将如何对齐 例如,下面的代码声明了4个类。前2个字节各为16个字节。但是3是48字节,尽管它包含与前2相同的数据成员。虽然第四个类与第三个类具有相同的数据成员,只是顺序不同,但它是32字节 #include <xmmintrin.h> #include <stdio.h> class TestClass1 { __m128i vect; }; class TestClass2 { char b

详细信息

我试图理解确定一个类将使用多少内存的规则是什么,以及内存将如何对齐

例如,下面的代码声明了4个类。前2个字节各为16个字节。但是3是48字节,尽管它包含与前2相同的数据成员。虽然第四个类与第三个类具有相同的数据成员,只是顺序不同,但它是32字节

#include <xmmintrin.h>
#include <stdio.h>

class TestClass1 {
  __m128i vect;
};

class TestClass2 {
  char buf[8];
  char buf2[8];
};

class TestClass3 {
  char buf[8];
  __m128i vect;
  char buf2[8];
};

class TestClass4 {
  char buf[8];
  char buf2[8];
  __m128i vect;
};


TestClass1 *ptr1;
TestClass2 *ptr2;
TestClass3 *ptr3;
TestClass4 *ptr4;
int main() {
  ptr1 = new TestClass1();
  ptr2 = new TestClass2();
  ptr3 = new TestClass3();
  ptr4 = new TestClass4();
  printf("sizeof TestClass1 is: %lu\t TestClass2 is: %lu\t TestClass3 is: %lu\t TestClass4 is: %lu\n", sizeof(*ptr1), sizeof(*ptr2), sizeof(*ptr3), sizeof(*ptr4));
  return 0;
}
#包括
#包括
类TestClass1{
__m128i向量;
};
类TestClass2{
char-buf[8];
char-buf2[8];
};
类TestClass3{
char-buf[8];
__m128i向量;
char-buf2[8];
};
类TestClass4{
char-buf[8];
char-buf2[8];
__m128i向量;
};
TestClass1*ptr1;
TestClass2*ptr2;
TestClass3*ptr3;
TestClass4*ptr4;
int main(){
ptr1=新的TestClass1();
ptr2=新的TestClass2();
ptr3=新的TestClass3();
ptr4=新的TestClass4();
printf(“sizeof TestClass1是:%lu\t TestClass2是:%lu\t TestClass3是:%lu\t TestClass4是:%lu\n”,sizeof(*ptr1),sizeof(*ptr2),sizeof(*ptr3),sizeof(*ptr4));
返回0;
}
我知道答案与类中数据成员的对齐有关。但是我试图准确地理解这些规则是什么,以及它们在编译步骤中是如何应用的,因为我有一个类,它有一个
\uum128i
数据成员,但数据成员不是16字节对齐的,当编译器使用
movaps
来访问数据时,这会导致segfault(普通旧数据),规则通常为:

  • 结构中的每个构件都有一些尺寸s和一些对齐要求a
  • 编译器首先将大小S设置为零,将对齐要求设置为1(字节)
  • 编译器按顺序处理结构中的每个成员:
  • 考虑成员的对齐要求a。如果s当前不是a的倍数,则添加足够的字节s,使其成为a的倍数。这决定了成员将去哪里;它将去结构开始处的偏移量s(对于s的当前值)
  • 将A设置为A和A的最小公倍数
  • 将s添加到s,以便为成员留出空间
  • 当为每个成员完成上述过程时,考虑结构的对齐要求。如果S不是当前的A的倍数,那么只需加上S,以使它是A/< LI>的倍数。
完成上述操作后,结构的大小为S的值

此外:

  • 如果任何成员是数组,则其大小是元素数乘以每个元素的大小,其对齐要求是元素的对齐要求
  • 如果任何构件是结构,其尺寸和对齐要求按上述方法计算
  • 如果任何成员是工会:
  • 将S设置为最大成员的大小
  • 将A设置为所有成员路线的最小公倍数
  • 如果S不是a的倍数,则添加足够的S使其成为a的倍数
考虑一下您的
TestClass3

  • S从0开始,A从1开始
  • char buf[8]
    需要8个字节和对齐1,因此S增加8到8,A保持1
  • \uuu m128i vect
    需要16个字节和16个对齐方式。首先,必须将S增加到16以获得正确的对齐方式。然后必须将A增加到16。然后,必须将S增加16以为
    vect
    留出空间,因此S现在是32
  • char buf2[8]
    需要8个字节和对齐1,因此S增加8到24,A保持16
  • 最后,S是24,这不是a(16)的倍数,因此S必须增加8到32
因此,
TestClass3
的大小是32字节

#include <xmmintrin.h>
#include <stdio.h>

class TestClass1 {
  __m128i vect;
};

class TestClass2 {
  char buf[8];
  char buf2[8];
};

class TestClass3 {
  char buf[8];
  __m128i vect;
  char buf2[8];
};

class TestClass4 {
  char buf[8];
  char buf2[8];
  __m128i vect;
};


TestClass1 *ptr1;
TestClass2 *ptr2;
TestClass3 *ptr3;
TestClass4 *ptr4;
int main() {
  ptr1 = new TestClass1();
  ptr2 = new TestClass2();
  ptr3 = new TestClass3();
  ptr4 = new TestClass4();
  printf("sizeof TestClass1 is: %lu\t TestClass2 is: %lu\t TestClass3 is: %lu\t TestClass4 is: %lu\n", sizeof(*ptr1), sizeof(*ptr2), sizeof(*ptr3), sizeof(*ptr4));
  return 0;
}

对于基本类型(
int
double
,等等),对齐要求取决于实现,并且在很大程度上取决于硬件。在许多处理器上,当数据具有特定对齐时(通常当其内存地址是其大小的倍数时),加载和存储数据的速度更快。除此之外,上述规则主要遵循逻辑;它们将每个成员放在必须满足对齐要求的位置,而不使用超出必要的空间。

如果要确保对齐,应在h文件中使用“pragma pack(1)” 请看这篇文章:

这些规则是由正在使用的应用程序二进制接口规范一成不变地制定的,该规范确保了共享此接口的程序在不同系统之间的兼容性

对于GCC,这是安腾ABI


(不幸的是,它不再公开,尽管我确实发现了。)

这完全取决于编译器如何确定类的大小。编译器通常会编译以匹配特定的应用程序二进制接口,这取决于平台

但是,您观察到的行为非常典型。编译器正在尝试对齐成员,以便每个成员以其大小的倍数开始。对于
TestClass3
,其中一个成员的类型为
\uuum128i
sizeof(\uuuuuuum128i)==16
。因此它将尝试对齐该成员,使其从16的倍数开始。第一个成员的类型为
char[8]
,因此占用8个字节。如果编译器将
\u m128i
对象直接放在第一个成员之后,它将从位置8开始,而不是16的倍数:

0               8               16              24              32              48
┌───────────────┬───────────────────────────────┬───────────────┬┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│    char[8]    │            __m128i            │    char[8]    │           
└───────────────┴───────────────────────────────┴───────────────┴┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
因此,它更愿意这样做:

0               8               16              24              32              48
┌───────────────┬┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┬───────────────────────────────┬───────────────┐┄┄┄
│    char[8]    │               │           __m128i             │    char[8]    │
└───────────────┴┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┴───────────────────────────────┴───────────────┘┄┄┄
这使其大小为48字节

当您重新排列成员以获得
TestClass4
时,布局将变为:

0               8               16              24              32              48
┌───────────────┬───────────────┬───────────────────────────────┬┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
│    char[8]    │    char[8]    │           __m128i             │        
└───────────────┴───────────────┴───────────────────────────────┴┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
现在所有东西都已正确对齐-阵列的偏移量为1(t)的倍数