sizeof和alignof有什么区别?

时间:2012-07-08 21:40:05

标签: c++ c++11 sizeof alignof

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

我想我不知道对齐是什么......?

8 个答案:

答案 0 :(得分:62)

嗯,“内存”基本上是一个巨大的字节数组。但是,大多数较大的东西(如整数)需要超过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不正确;尝试结构。结构也将对齐(因为他们的个人成员需要以正确的地址结束),但它们的大小会更大。

答案 1 :(得分:15)

这两家运营商从根本上做了不同的事情。 sizeof给出了类型的大小(需要多少内存),而alignof给出了类型必须对齐的字节数。只是碰巧你测试的基元的对齐要求与它们的大小相同(如果你考虑它就有意义)。

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

struct Foo {
     int a;
     float b;
     char c;
};

alignof(Foo)将返回4.

答案 2 :(得分:10)

旧问题(虽然没有标记为已回答......)但是认为这个例子除了Christian Stieber的答案之外还有点明显。此外,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

它还表明,最好按大小排序成员,最大的是第一个(在这种情况下是双倍),因为其他成员受到该成员的约束。

答案 3 :(得分:8)

对于提供的答案,似乎对 alignment 实际上是什么感到困惑。可能会产生混淆,因为有两种对齐方式。

<强> 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字节对齐。

有两种填充机制可以实现打包。

  1. 首先,字节大小小于字节对齐的每个成员都会被合并&#39;如果结果字节大小小于或等于字节对齐,则使用下一个成员。在结构B中,成员s和c可以这种方式合并;对于c == 3字节&lt; = 4字节对齐,它们的组合大小是s + 1字节的2字节。对于结构A,不会发生这样的合并,并且每个成员在结构的包装中有效地消耗4个字节。

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

  3. 请注意,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的倍数结尾的地址上。

    使用这种分配对齐的原因再次纯粹是架构。例如,从页面对齐的地址读取和写入块更快,因为地址范围非常适合缓存层。分布在不同页面上的范围&#39;跨越页面边界时删除缓存。不同的媒体(总线架构)具有不同的访问模式,并且可以受益于不同的对齐。通常,4,16,32和64 K页面大小的对齐并不罕见。

答案 4 :(得分:6)

alignof值与基本类型的sizeof值相同。

不同之处在于使用定义的数据类型,例如使用struct;例如

typedef struct { int a; double b; } S;
//cout<<alignof(s);                              outputp: 8;
//cout<<sizeof(S);                               output: 12;

因此sizeof值是给定数据类型所需的总大小; 和alignof值是结构中最大元素的对齐要求。

使用alignof:在特定的对齐边界上分配内存。

答案 5 :(得分:2)

sizeof operator为您提供实际类型或类型实例的字节大小。

alignof operator为您提供给定类型的任何实例所需的字节对齐。

答案 6 :(得分:0)

  

sizeofalignof有什么区别?

两者都是运算符。两者都返回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

答案 7 :(得分:0)

数据在内存中按特定顺序排列,以便 CPU 访问。

  • alignof 通知对象在内存中的位置
  • sizeof 表示对象有多大,同时考虑其部件的位置

基本类型对于 alignofsizeof 具有相同的结果,因为它们仅作为自身的一部分: 例如。 short 占用 2 个字节并从 2 的地址倍数开始(对 CPU 有益)。 对于用户定义的数据类型,请查看它们的部分:

class Foo {
  char c1; // first member (imagine adr=0, which is multiple of 1, CPU is happy)
  int i; // adr=1, but adr has to be a multiple of 4, so reserve helper bytes for CPU (padding) before `i` = 3bytes. **so adr=4**
  short s; // adr=8 (adr of `i` + its size), 8 % 2 == 0, good
  double d; // adr=10 (adr of `s` + its size), 10 % 8 != 0, need 6 more, **so adr=16**
  char c2; // adr=24 (adr of `d` + its size), 24 % 1 == 0, ok

  // and surprise, after c2 padding is also needed! why?
  // imagine you have an array (which is sequentially data in memory) of 2 elements,
  // what is adr `d` of the second element? (let me use index=2 here)  
  // arr[2].c1 adr=25, arr[2].i adr=29 (?do you remember about padding=3bytes?, and this field already feels bad), ..., arr[2].d adr=31
  // must be padding after `c2` to satisfy everyone
  // calc p (padding), where (adr`c2` + size`c2` + p) % max(alignof of every member type) = (24+1+p) % 8 == 0; p=7 (minimum value that satisfies)   
  // YEAH! Now all members of all elements will be aligned!
};

如上所说,alignof(type) 是 CPU 对数据放置位置的偏好,在示例中:alignof(Foo)==alignof(double)=8 [否则某些成员会伤心]。
sizeof(Foo)==(每个成员大小的总和 + 填充)=32
ps。为了理解这个想法进行了允许的简化:)