【问题标题】:sizeof behaving unexpectedlysizeof 行为异常
【发布时间】:2011-01-13 13:04:01
【问题描述】:

考虑以下代码:

  #include <stdio.h>
  int main(void)
  {
    int a[10];
    printf("%d",(int)sizeof(a)); //prints 10*sizeof(int) (40 on my compiler)
    printf("%d",(int)sizeof(a-3)); //prints sizeof(int) (4 on my compiler)

  }

我知道sizeof() 是一个编译时运算符,但我很惊讶地看到第二个printf() 的输出。可能是什么原因? sizeof() 的参数是否从数组类型隐式转换为整数类型?

【问题讨论】:

  • 第二个实际打印的是sizeof(int *),而不是sizeof(int)sizeof(int *) 在你的平台上恰好也是 4 岁。
  • 另外,打印size_t 值(sizeof 返回的值)的正确方法是使用"%zu",假设您的编译器支持特定的 C99 功能。如果没有,更好的选择是将其转换为 unsignedunsigned long

标签: c


【解决方案1】:

sizeof 运算符不计算其参数,它只计算其操作数的 looks at the type

假设您有一个数组a,其类型为“T 型数组[N]”。那么,在大多数情况下,名称a 的类型是“指向T 的指针”(T *),而指针的值是数组第一个元素的地址(&amp;a[0])。也就是说,数组的名称“衰减”为指向其第一个元素的指针。在以下情况下不会发生“腐烂”:

  • a 与地址-of (&amp;) 运算符一起使用时,
  • a的初始化中(在C中赋值给数组是非法的),并且
  • asizeof 运算符的操作数时。

所以,sizeof a 给你Nsizeof(T)

当您执行sizeof(a-3) 时,sizeof 的操作数类型由表达式a-3 确定。由于a-3 中的avalue context 中使用(即上述三个上下文都没有),所以它的类型是“指向int 的指针”,而名称a 衰减为指向a[0] 的指针。因此,计算a-3 是未定义的行为,但由于sizeof 不评估其参数,a-3 仅用于确定操作数的类型,因此代码是可以的(有关更多信息,请参见上面的第一个链接)。

从上面看,sizeof(a-3) 等价于sizeof(int *),也就是你电脑上的4。

“转换”是由于减法运算符。您可以使用逗号运算符看到类似的,也许更令人惊讶的结果:

printf("%zu\n", sizeof(1, a));

还将打印sizeof(int *),因为逗号运算符导致a 在值上下文中使用。

【讨论】:

    【解决方案2】:

    (a-3) 的类型为 int*,它会在您的平台上打印您的 sizeof(int*),即 4。

    请注意,sizeof() 在 C99 中不再是编译时常量(由于可变长度数组)。

    【讨论】:

    • 需要明确 - 只有当操作数是可变长度数组时,sizeof 的结果才不是编译器时间常数。对于其他操作数类型,它仍然是一个常量。
    【解决方案3】:

    不,在第二种情况下,参数被解释为 int* 指针,它在您的机器上的大小恰好也等于 4。

    【讨论】:

      【解决方案4】:

      sizeof() 返回类型的大小,因此类型很重要。

      它也不应该用%d 打印。至少,将其显式转换为 unsigned longunsigned long long 并使用适当的格式说明符。在教 C 的时候,我有一个学生把 size_t%d 打印成错误的答案,就像教科书上错误所说的那样。

      不管怎样,a 是一个数组类型。在 C 中,如果您对数组类型进行几乎任何操作或大声打喷嚏,则数组类型会衰减为指针类型,因此您对a 所做的几乎所有操作都会产生指针类型。正如您所发现的,添加或减去一个数字会衰减。 (毕竟算术中不能使用数组,但是指针可以。)

      【讨论】:

      • @David:只要结果不溢出,如果将表达式转换为(int),那么用"%d" 打印它就可以了。在这种情况下,几乎可以肯定该大小适合int。在 C99 中,当然可以使用 "%zu"。对于 C89,您的建议比在转换为 (int) 后使用 "%d" 打印更好,因为它更容易溢出。
      • @Alok: 没错,但是做演员比你演员要重要得多。另外,我对 C89 非常熟悉,并没有使用过 C99,它可能会显示。
      • OP 在他的问题中有演员表。我同意你的看法——没有演员表,"%d" 是错误的,但是只要没有溢出,OP 的 printf() 调用就可以了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-05
      • 2017-01-22
      • 2013-04-14
      • 2014-01-29
      • 1970-01-01
      • 2010-10-14
      • 2011-09-10
      相关资源
      最近更新 更多