sizeof和alignof有什么区别?
#include <iostream>
#define SIZEOF_ALIGNOF(T) std::cout<< sizeof(T) << '/' << alignof(T) << std::endl
int main(int, char**)
{
SIZEOF_ALIGNOF(unsigned char);
SIZEOF_ALIGNOF(char);
SIZEOF_ALIGNOF(unsigned short int);
SIZEOF_ALIGNOF(short int);
SIZEOF_ALIGNOF(unsigned int);
SIZEOF_ALIGNOF(int);
SIZEOF_ALIGNOF(float);
SIZEOF_ALIGNOF(unsigned long int);
SIZEOF_ALIGNOF(long int);
SIZEOF_ALIGNOF(unsigned long long int);
SIZEOF_ALIGNOF(long long int);
SIZEOF_ALIGNOF(double);
}
将输出
1/1 1/1 2/2 2/2 4/4 4/4 4/4 4/4 4/4 8/8 8/8 8/8
我想我不知道对齐是什么......?
好吧,“内存”基本上是一个巨大的字节数组。但是,大多数较大的东西(如整数)需要超过1个字节来存储它们 - 例如,32位值将使用4个连续字节的内存。
现在,计算机中的内存模块通常不是“字节”;它们也被组织成几个字节“并行”,就像4个字节的块一样。
对于CPU来说,它更容易=效率更高=在读取类似整数时不会“交叉”这样的块边界的更好性能:
memory byte 0 1 2 3 4 5 6 7 8 9 10 11
integer goooood
baaaaaaaaad
这就是“对齐”所说的:4的对齐意味着这种类型的数据应该(或必须,取决于CPU)从4的倍数地址开始存储。
你观察到sizeof == alignof是不正确的;尝试结构。结构也将对齐(因为它们各自的成员需要以正确的地址结束),但它们的大小会更大。
这两个运营商做了根本不同的事情。 sizeof
给出了一个类型的大小(需要多少内存),而alignof
给出了一个类型必须对齐的字节数。事实上,您测试的基元的对齐要求与它们的大小相同(如果您考虑它,这是有意义的)。
想想如果你有一个结构会发生什么:
struct Foo {
int a;
float b;
char c;
};
alignof(Foo)
将返回4。
旧问题(虽然没有标记为已回答......)但是认为这个例子除了克里斯蒂安施蒂伯的答案之外还有点明显。 Meluha的答案也包含一个错误,因为sizeof(S)输出是16而不是12。
// c has to occupy 8 bytes so that d (whose size is 8) starts on a 8 bytes boundary
// | 8 bytes | | 8 bytes | | 8 bytes |
struct Bad { char c; double d; int i; };
cout << alignof(Bad) << " " << sizeof(Bad) << endl; // 8 24
// | 8 bytes | | 8 bytes |
struct Good { double d; int i; char c; };
cout << alignof(Good) << " " << sizeof(Good) << endl; // 8 16
它还表明,最好按大小排序成员,最大的是第一个(在这种情况下为double),因为其他成员受到该成员的约束。
对于提供的答案,似乎存在一些关于实际对齐的混淆。可能会出现混淆,因为有两种对齐方式。
1.成员对齐
这是一个定性度量,它说明了实例在结构/类类型中成员的特定排序的字节数有多大。通常,如果成员按结构中的降序(即最大的第一个,最小的成员)按字节大小排序,则编译器可以压缩结构/类实例。考虑:
struct A
{
char c; float f; short s;
};
struct B
{
float f; short s; char c;
};
两种结构都包含完全相同的信息。为了这个例子; float类型需要4个字节,short类型需要2个字符,字符需要1个字节。但是,第一个结构A具有随机顺序的成员,而第二个结构B根据它们的字节大小对成员进行排序(这在某些体系结构上可能不同,我假设x86 intel CPU体系结构在此示例中具有4字节对齐)。现在考虑结构的大小:
printf("size of A: %d", sizeof (A)); // size of A: 12;
printf("size of B: %d", sizeof (B)); // size of B: 8;
如果您希望大小为7个字节,则可以假设成员使用1字节对齐方式打包到结构中。虽然有些编译器允许这样做,但由于历史原因(大多数CPU使用DWORD(双字)或QWORD(四字)通用寄存器),大多数编译器通常使用4字节甚至8字节对齐。
有2个填充机制在工作以实现包装。
请注意,Visual C ++ / GCC允许1个字节的不同对齐,2个字节的2倍和更高倍数。了解这会影响编译器为您的架构生成最佳代码的能力。实际上,在下面的示例中,对于每个读取操作,使用单字节指令将每个字节读取为单个字节。实际上,硬件仍然会获取包含读入高速缓存的每个字节的整个存储器行,并执行指令4次,即使4个字节位于同一个DWORD中并且可以在1个指令中加载到CPU寄存器中。
#pragma pack(push,1)
struct Bad
{
char a,b,c,d;
};
#pragma pack(pop)
2.分配对齐
这与前一节中解释的第二填充机制密切相关,但是,可以在malloc / memalloc分配函数的变体中指定分配对齐,例如,释放calloc。因此,可以在与结构/对象类型的字节对齐建议不同的(通常更高的2倍)对齐边界处分配对象。
size_t blockAlignment = 4*1024; // 4K page block alignment
void* block = calloc(sizeof(T) * count, blockAlignment);
代码将把类型为T的计数实例块放在以4096的倍数结束的地址上。
使用这种分配对齐的原因再次纯粹是架构。例如,从页面对齐的地址读取和写入块更快,因为地址范围非常适合缓存层。分割在不同“页面”上的范围在跨越页面边界时会丢弃缓存。不同的媒体(总线架构)具有不同的访问模式,并且可以受益于不同的对齐。通常,4,16,32和64 K页面大小的对齐并不罕见。
alignof值与基本类型的sizeof值相同。
不同之处在于使用定义的数据类型,例如使用struct;例如
typedef struct { int a; double b; } S;
//cout<<alignof(s); outputp: 8;
//cout<<sizeof(S); output: 12;
因此sizeof值是给定数据类型所需的总大小;和alignof值是结构中最大元素的对齐要求。
使用alignof:在特定的对齐边界上分配内存。
sizeof
operator为您提供实际类型或类型实例的字节大小。
alignof
operator为您提供给定类型的任何实例所需的字节对齐。
sizeof
和alignof
有什么区别?
两者都是运营商。两者都返回一种size_t
。
sizeof
是对象的“字节”大小 - 编码它所需的内存空间。
alignof
是对象“字节”中的地址对齐要求。值1表示没有对齐限制。 2表示地址应该是偶数地址。 4表示地址应为四元地址。等等
当尝试对象引用不符合对齐要求时,结果是未定义的行为。 例子: 。访问可能有效,但速度较慢。 。访问尝试可能会终止程序。
// Assume alignof(int) --> 2
char a[4]; // It is not known that `a` begins on an odd or even address
int *p = a; // conversion may fail
int d = *p; // *p is UB.
OP代码的示例扩展和输出。
SIZEOF_ALIGNOF(double);
SIZEOF_ALIGNOF(complex double);
SIZEOF_ALIGNOF(div_t);
SIZEOF_ALIGNOF(max_align_t);
8/8
16/8
8/4
32/16