sizeof表现出乎意料
请考虑以下代码:
#include 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
运算符不会计算其参数,只会查看其操作数的类型 。
假设你有一个数组类型为“类型为T的数组[N]”。 然后,在大多数情况下,名称a
的类型是“指向T的指针”( T *
),指针的值是数组的第一个元素的地址( &a[0]
)。 也就是说,数组的名称“衰减”为指向其第一个元素的指针。 在下列情况下不会发生“腐朽”:
- 当
a
与地址(&
)运算符一起使用时, - 在a的初始化中(在C中分配给数组是非法的),和
- 当
a
是sizeof
运算符的操作数时。
因此, sizeof a
给出N
次sizeof(T)
。
当你执行sizeof(a-3)
, sizeof
的操作数类型由表达式a-3
确定。 由于a
a-3
在值上下文中使用 (即,上述三个上下文中没有一个),因此其类型为“指向int的指针”,并且名称a
衰减为指向a[0]
的指针。 因此,计算a-3
是未定义的行为,但由于sizeof
不计算其参数,因此a-3
仅用于确定操作数的类型,因此代码正常(请参阅上面的第一个链接以获取更多信息)。
从上面可以看出, sizeof(a-3)
相当于sizeof(int *)
,在你的计算机上是4。
“转换”是由减法运算符引起的。 您可以使用逗号运算符查看类似的,也许更令人惊讶的结果:
printf("%zu\n", sizeof(1, a));
还将打印sizeof(int *)
,因为逗号运算符导致在值上下文中使用。
(a-3)
类型为int*
,它会在平台上打印sizeof(int*)
,它是4。
请注意, sizeof()
在C99中不再是编译时常量(由于可变长度数组)。
不,在第二种情况下,参数被解释为一个int*
指针,它的机器上的大小也恰好等于4。
sizeof()
返回类型的大小,因此类型是重要的。
它也不应该用%d
打印。 至少,明确地将它转换为unsigned long
或unsigned long long
并使用适当的格式说明符。 当教C时,我有一个学生通过打印size_t
和%d
得到了错误的答案,正如教科书错误地说的那样。
无论如何, a
是一种数组类型。 在C中,如果你几乎用它们做任何事情或大声打喷嚏,数组类型会衰减为指针类型,所以你对a
做的几乎任何事都会产生一个指针类型。 正如您所知,增加或减少数字会衰减。 (毕竟,数组不能用于算术,但指针可以。)