为什么我没有得到与使用%d
而不是使用相同的价值%f
?
void main()
{
int arr;
printf("%f",sizeof(arr));
}
输出: 2.168831
void main()
{
int arr;
printf("%d",sizeof(arr));
}
输出:4
为了给出更多解释,这是因为printf()
是一个可变参数函数,并且在函数运行并从格式字符串中确定它们是什么之前,参数的类型是未知的。这意味着不会发生正常的隐式转换。
例如,如果您执行以下操作:
void myfunc(double d) {
/* Do something with d */
}
int main(void) {
int n = 5;
myfunc(n);
return 0;
}
然后编译器知道它myfunc()
接受一个类型的参数double
,因此可以并且将在传递参数之前隐式转换为n
。int
double
当你这样做时:
int main(void) {
double f = 5.5;
printf("%d\n", f); /* WARNING: buggy code */
return 0;
}
编译器在printf()
运行并理解%d
格式字符串中的 之前不知道期望什么类型。因此,它所能做的就是将double
参数作为 a传递double
,当printf()
运行并看到时%d
,它会将其解释int
为论点,以及,把它扔给它之后的任何其他论点)。
这就是为什么这些函数是 C 中实际需要强制转换的少数情况之一的原因void *
,因为指向不同类型对象的指针允许具有不同的大小,并且由于%p
期望 a void *
,因此您必须通过它是一个void *
,而不是指向任何其他对象类型的指针。
但是请注意,现代编译器可能很聪明,并且他们知道标准 C 函数是如何工作的,因此他们可以只了解函数的标准行为,printf()
这样他们就可以向您发出有关此类参数类型不匹配的警告,尽管他们赢了'实际上并没有为你修复它们。
sizeof
返回size_t
但printf("%f",...
告诉printf
下一个参数有 type double
。 size_t
在内存中有不同的布局,double
因此printf
错误地解释了这个论点。
正如 Grijesh 指出的那样,正确的格式说明符应该是%zu
,但如果你真的想使用%f
printf("%f",(double)sizeof(arr));
会工作
sizeof
运算符返回`size_t
您应该使用%zu
格式说明符printf()
请注意,size_t
大小可以用 表示。unsigned
signed
ssize_t
这两种类型都在stddef.h
标头中定义
C11 标准的 §7.21.6.1 p9说
如果转换规范无效,则行为未定义。如果任何参数不是相应转换规范的正确类型,则行为未定义。