首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >sizeof和alignof有什么区别?

sizeof和alignof有什么区别?
EN

Stack Overflow用户
提问于 2012-07-09 05:40:05
回答 8查看 18K关注 0票数 61

sizeof和alignof有什么区别?

代码语言:javascript
复制
#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 8/8 8/8 8/8

我想我不明白什么是对齐...?

EN

回答 8

Stack Overflow用户

发布于 2012-07-09 05:48:52

嗯,“内存”基本上是一个巨大的字节数组。然而,大多数更大的东西,如整数,需要超过1个字节来存储它们--例如,一个32位的值将使用4个连续的字节的内存。

现在,计算机中的内存模块通常不是“字节”的;它们也是由几个字节“并行”组织的,就像4个字节的块。

对于CPU,在读取像整数这样的东西时,不“跨越”这样的块边界要容易得多,效率更高,性能更好:

代码语言:javascript
复制
memory byte    0 1 2 3     4 5 6 7       8 9 10 11
 integer       goooood
                   baaaaaaaaad

这就是“对齐”所说的:对齐4意味着这种类型的数据应该(或必须取决于CPU)从4的倍数的地址开始存储。

您观察到sizeof==alignof是不正确的;请尝试结构。结构也将对齐(因为它们的单个成员需要在正确的地址上结束),但它们的大小将大得多。

票数 80
EN

Stack Overflow用户

发布于 2016-12-01 19:14:14

对于所提供的答案,似乎有一些关于对齐实际是什么的困惑。混淆可能是因为有两种对齐方式。

1.成员对齐

这是一种定性度量,它用字节数来表示实例在结构/类类型中的特定成员排序有多大。通常,如果成员在结构中按字节大小降序排序(即最大的成员在前面,最小的成员在最后),编译器可以压缩结构/类实例。考虑一下:

代码语言:javascript
复制
struct A
{
  char c; float f; short s;
};

struct B
{
  float f; short s; char c;
};

这两个结构包含完全相同的信息。就本例而言,float类型占用4个字节,short类型占用2个字节,而character占用1个字节。但是,第一个结构A具有随机顺序的成员,而第二个结构B根据成员的字节大小对成员进行排序(这在某些体系结构上可能不同,在本例中我假设x86英特尔CPU体系结构具有4字节对齐)。现在考虑结构的大小:

代码语言:javascript
复制
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字节对齐。

有两个填充机制在工作,以实现包装。

  1. 首先,如果得到的字节大小小于或等于字节对齐,则将字节大小小于字节对齐的每个成员与下一个成员“合并”。在结构B中,成员s和c可以这样合并:对于s,它们的组合大小是2字节;对于c == 3字节和4字节对齐,它们的组合大小是1字节。对于结构A,不可能发生这样的合并,并且每个成员实际上消耗了结构的包装中的4个字节。

  1. 再次填充结构的总大小,以便下一个结构可以从对齐边界开始。在示例B中,总字节数为7。下一个4字节边界位于字节8,因此该结构填充了1个字节,以允许将数组分配作为实例的紧密序列。

请注意,Visual C++ / GCC允许1字节、2字节和2字节的更高倍数的不同对齐。要知道,这与编译器为体系结构生成最佳代码的能力背道而驰。实际上,在下面的示例中,对于每个读取操作,将使用单字节指令将每个字节读取为单个字节。在实践中,硬件仍将取出包含读取到高速缓存中的每个字节的整个存储器线,并执行指令4次,即使这4个字节位于相同的DWORD中并且可以在1条指令中加载到CPU寄存器中。

代码语言:javascript
复制
#pragma pack(push,1)
struct Bad
{
  char a,b,c,d;
};
#pragma pack(pop)

2.分配对齐

这与上一节中解释的第二个填充机制密切相关,但是,分配对齐可以在malloc() / memalloc()分配函数的变体中指定,例如std::aligned_alloc()。因此,可以在结构/对象类型的字节对齐建议的不同(通常是2的较高倍数)对齐边界上分配对象。

代码语言:javascript
复制
size_t blockAlignment = 4*1024;  // 4K page block alignment
void* block = std::aligned_alloc(blockAlignment, sizeof(T) * count);

代码将把类型T的count实例块放在以4096的倍数结尾的地址上。

使用这种分配对齐的原因也是纯粹的架构。例如,从页面对齐的地址读取和写入块的速度更快,因为地址范围非常适合缓存层。当跨越页面边界时,拆分到不同“页面”上的范围将回收缓存。不同的介质(总线架构)具有不同的访问模式,并且可以从不同的对齐中受益。通常,4、16、32和64K页面大小的对齐并不少见。

请注意,语言版本和平台通常会提供这种对齐分配函数的特定变体。例如,Unix/Linux兼容的posix_memalign()函数通过ptr参数返回内存,并在失败的情况下返回非零的错误值。

空对齐整数对齐( // POSIX(Linux/UX)

  • void **
  • ,posix_memalign,size_t size_t *aligned_alloc );空对齐( size_t size_t,size_t *aligned_alloc );空对齐( size_t size_t,*std::aligned_alloc );空对齐( size_t size_t,*aligned_malloc);void对齐(size_t*aligned_alloc,size_t*aligned_malloc);void
票数 23
EN

Stack Overflow用户

发布于 2012-07-09 05:45:31

这两个运算符做的是完全不同的事情。sizeof给出了一个类型的大小(它需要多少内存),而alignof给出了一个类型必须与多少字节对齐。碰巧您测试的原语具有与其大小相同的对齐要求(如果您仔细考虑一下,这是有意义的)。

想一想,如果你有一个结构,会发生什么:

代码语言:javascript
复制
struct Foo {
     int a;
     float b;
     char c;
};

alignof(Foo)将返回4。

票数 19
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11386946

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档