sizeof如何计算结构体的大小

13

我知道在32位架构下,由于对齐方式的影响,char和int的大小都被计算为8个字节。但最近我遇到了这样一种情况:一个拥有3个short的结构体通过sizeof操作符报告其大小为6个字节。代码如下:

#include <iostream>
using namespace std ;

struct IntAndChar
{
    int a ;
    unsigned char b ;
};


struct ThreeShorts
{
    unsigned short a ;
    unsigned short b ;
    unsigned short c ;
};


int main()
{
    cout<<sizeof(IntAndChar)<<endl; // outputs '8'
    cout<<sizeof(ThreeShorts)<<endl; // outputs '6', I expected this to be '8'
    return 0 ;
}

编译器:g++(Debian 4.3.2-1.1)4.3.2。这真的让我感到困惑,为什么包含3个short的结构体没有执行对齐?

6个回答

22

这是因为 int 占用 4 字节,必须对齐到 4 字节边界。这意味着任何包含 intstruct 也必须至少对齐到 4 字节。

另一方面,short 占用 2 字节,只需要对齐到 2 字节边界。如果一个仅包含 shortstruct 不包含任何需要更大对齐的成员,那么该 struct 也将对齐到 2 字节。


15

这真的让我感到困惑,为什么t没有强制对齐

你想要它具有什么样的对齐方式?

短整型可以在2字节边界上对齐,不会产生任何副作用(假设常见的x86编译器都在这里)。因此,如果你创建一个struct ThreeeShorts数组,其大小为6是可以的,因为这样数组中的任何元素都将从2字节边界开始。

你的struct IntAndChar包含一个int,int需要4字节对齐,因此如果你创建一个struct IntAndChar数组,则下一个元素的大小必须为8,以便对齐到4字节边界。

如果我们不考虑数组,那么struct IntAndChar长度为5字节并不重要,当你在堆栈上创建一个结构体或将其用作另一个结构体的复合成员时,编译器只需从4字节边界开始分配即可。

你总是可以通过执行sizeof(arrayofT)/sizeof(T)来获得数组中元素的数量,并且数组元素保证相邻存储,因此第n个元素可以通过从开头步进N*sizeof(arrayelementtype)字节来检索,这也是你会看到结构体在末尾填充的主要原因。


我并不想要任何特定的对齐方式,只是我认为在32位架构上始终遵守4字节对齐。 - Gearoid Murphy
如果能这样就好了!这肯定会让编写内存分配器变得更容易...不幸的是,不同类型的对齐方式可能不同,并且没有可移植的方法来询问编译器有关给定类型的特定对齐方式,尽管有一些技巧。 - Matthieu M.
#define alignof(type) ((char *)&((struct { char dummy; type x; } *)0)->x - (char *)0) - R.. GitHub STOP HELPING ICE

6
我不知道你从哪里得到了关于charint被计算为"8字节"的想法。不,每种类型都是根据其大小进行计算的:char为1,在32位平台上int为4(不是8,而是4)。每种类型的对齐要求通常与其大小相同(尽管不一定要这样)。
因此,当结构包含相同类型的成员时,该结构的总大小通常将是其成员大小的精确总和:一个由3个char组成的结构将具有大小3,而由两个int组成的结构将具有大小8。
显然,你的平台上short类型的大小为2,因此,预期地,由3个shorts组成的结构的大小为6,这正是你观察到的大小。
但是,当你的结构包含不同类型的成员时,不同类型之间对齐要求的差异就会发挥作用。如果下一个字段的对齐要求比前一个字段的对齐要求更严格,则编译器可能必须在这些字段之间添加一些填充字节(以正确对齐下一个成员),这将影响结构体的最终大小。此外,编译器可能必须在结构的最后一个成员之后添加一些额外的填充字节,以满足数组中的对齐要求。
例如,一个看起来像下面这样的结构体:
struct S {
  char c;
  int i;
};

由于需要在char成员后添加3个填充字节,因此在您的平台上,该结构体最可能占用8个字节。请注意,char计为1,int计为4,它们之间的额外3个填充字节使其总大小为8。

还要注意,这很容易导致结构体的最终大小依赖于成员声明的顺序。例如,这个结构体:

struct S1 {
  char c1;
  int i;
  char c2;
};

您平台上的字体大小可能为12号,而这个字体大小

struct S2 {
  int i;
  char c1;
  char c2;
};

这个例子旨在说明结构体的最终大小不能仅根据每个成员所占用的字节数来计算,即使最后一个例子只占用8个字节。成员之间的关系也很重要。


2
完全取决于具体实现,但是假设您的系统可以访问结构体中的任何三个short而不必担心对齐问题,那么它就可以访问ThreeShorts数组中的任何short,因此也不必更严格地对齐结构体。
对于IntAndChar示例,假设int大小为4且实现关注其对齐方式。为确保IntAndChar数组中的每个int成员都正确对齐,必须填充结构体。
数组T[n]sizeof精确定义为sizeof(T) * n

1

是的,我也遇到了同样的问题。我有以下结构

struct Node{
    short digit;
    Node* next;
};
    cout<<":"<<sizeof(Node)<<":"<<sizeof(short)<<":"<<sizeof(Node*)<<endl;

这给了我 ::8:2:4 ?? 为什么结构的总和=8,但单个元素不相加?? 这是由于内存对齐,内存会填充额外的2个字节以进行对齐。 谢谢

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接