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