关于sizeof用法的问题

时间:2010-03-29 05:39:09

标签: c++ c sizeof

问题1

我有一个像

这样的结构
struct foo
{
    int a;
    char c;
};

当我说sizeof(foo)时,我的机器上有8。根据我的理解,int为4个字节,char为1个字节,填充为3个字节。那是对的吗?给定如上所述的结构,我将如何找出将添加多少字节作为填充?

问题2

我知道sizeof可以用来计算数组的大小。大多数情况下,我已经看到像(foos是一个foo

数组的用法
sizeof(foos)/sizeof(*foos)

但我发现以下内容也会给出相同的结果。

sizeof(foos) / sizeof(foo)

这两个有什么不同吗?哪一个更受欢迎?

问题3

请考虑以下声明。

foo foos[] = {10,20,30};

当我sizeof(foos) / sizeof(*foos)时,它会给出2.但是数组有3个元素。如果我将语句更改为

foo foos[] = {{10},{20},{30}};

它给出了正确的结果3.为什么会发生这种情况?

任何想法..

3 个答案:

答案 0 :(得分:21)

答案1

是的 - 您的计算是正确的。在您的计算机上,sizeof(int) == 4int必须是4字节对齐的。

您可以通过手动添加基本元素的大小并从sizeof()报告的大小中减去该大小来找到有关填充的信息。如果您知道机器上的对齐要求,则可以预测填充。请注意,某些计算机非常繁琐,并且在访问未对齐的数据时会出现SIGBUS错误;当你访问未对齐的数据时,其他人会更宽松,但会减慢你的速度(他们可能支持'#pragma packed'或类似的东西)。通常,基本类型的大小为2(1,2,4,8,16)的幂,并且n字节类型必须是n字节对齐的。此外,请记住,必须填充结构,以便结构数组将所有元素正确对齐。这意味着结构通常会被填充到结构中最严格对齐的构件的大小的倍数。

答案2

一般来说,第一个的变体更好;将数组的基本类型从'foo'更改为'foobar'时,它仍然是正确的。我通常使用的宏是:

#define DIM(x) (sizeof(x)/sizeof(*(x)))

其他人有相同基本操作的其他名称 - 你可以把我用过的名字放在昏暗和遥远的过去的污染和一些BASIC的使用。

像往常一样,有警告。最值得注意的是,您不能将这有意义地应用于函数的数组参数或动态分配的数组(使用malloc()等或new[]);你已经适用于数组的实际定义。通常,该值是编译时常量。在C99下,如果数组是VLA - 可变长度数组,则可以在运行时对其进行评估。

回答3

由于没有足够大括号时初始化的方式。你的'foo'结构必须有两个元素。 10和20被分配到第一行; 30和隐含的0被提供给第二行。因此,大小是两个。当你提供子括号时,数组中有3个元素,其中第一个组件的值为10,20,30,第二个组件都有零。

答案 1 :(得分:3)

  1. 填充通常与hist CPU上的寄存器大小有关 - 在你的情况下,你有一个32位的CPU,所以int的“自然”大小是4个字节。 CPU访问小于此大小的内存量更慢且更困难,因此通常最好将值对齐到4字节边界。因此,结构体的大小为4个字节的倍数。大多数编译器都允许你修改使用的填充量(例如使用“#pragma”),但这只应该在结构的内存占用绝对关键的情况下使用。

  2. “* foos”引用foos数组中的第一个条目。 “foo”引用(单个实例)类型。所以他们基本上是一样的。我自己会使用sizeof(type)或sizeof(array [0]),因为*数组更容易被误读。

  3. 在第一个示例中,您没有正确地初始化数组条目。您的结构有2个成员,因此您必须使用{a,b}初始化数组的每个成员。因此,您需要使用{{a,b},{a,b},{a,b}}表单来正确初始化条目。

答案 2 :(得分:2)

要找出你有多少填充,只需将sizeof()与结构的每个元素相加,然后从sizeof()整个结构中减去这个总和。

您可以使用offsetof()在更复杂的结构中找到填充的确切位置。这可以帮助您通过重新排列元素来填充空洞,从而减小整个结构的大小。

最好通过手动插入填充元素来显式对齐结构元素,以确保每个元素都“自然对齐”。您可以在将来重用这些填充元素以获取有用的数据。如果您编写的库需要稳定的ABI,这将是一项必需的技术。