C 为什么sizeof的响应与%f不同?
为什么我没有得到与C 为什么sizeof的响应与%f不同?,c,gcc,escaping,sizeof,C,Gcc,Escaping,Sizeof,为什么我没有得到与%d和%f相同的值 void main() { int arr; printf("%f",sizeof(arr)); } 输出:2.168831 void main() { int arr; printf("%d",sizeof(arr)); } 输出:4sizeof返回size\u t,但printf(“%f”),…告诉printf下一个参数的类型为doublesize\u t在内存中的布局与double不同,因此printf错误地解释了这个参
%d
和%f
相同的值
void main()
{
int arr;
printf("%f",sizeof(arr));
}
输出:2.168831
void main()
{
int arr;
printf("%d",sizeof(arr));
}
输出:
4
sizeof
返回size\u t
,但printf(“%f”),…
告诉printf
下一个参数的类型为double
size\u t
在内存中的布局与double
不同,因此printf
错误地解释了这个参数
正如Grijesh指出的,正确的格式说明符应该是%zu
,但是如果您真的想使用%f
printf("%f",(double)sizeof(arr));
将起作用
sizeof
返回size\u t
,但printf(“%f”)告诉printf
,下一个参数的类型为double
size\u t
在内存中的布局与double
不同,因此printf
错误地解释了这个参数
正如Grijesh指出的,正确的格式说明符应该是%zu
,但是如果您真的想使用%f
printf("%f",(double)sizeof(arr));
将工作
sizeof
运算符返回`size\u t
您应该使用%zu
格式说明符和printf()
请注意,size\u t
是unsigned
,signed
大小可以用ssize\u t
表示
这两种类型都在stddef.h
标题中定义
C11标准第7.21.6.1页
如果转换规范无效,则行为未定义
对应转换规范的类型不正确,行为为
未定义
sizeof
运算符返回`size\u t
您应该将%zu
格式说明符与printf()一起使用
请注意,size\u t
是unsigned
,signed
大小可以用ssize\u t
表示
这两种类型都在stddef.h
标题中定义
C11标准第7.21.6.1页
如果转换规范无效,则行为未定义
对应转换规范的类型不正确,行为为
未定义
更详细地解释一下,这是因为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;
}
编译器在运行并理解格式字符串中的%d
之前,不知道需要什么类型的printf()
。因此,它所能做的就是将double
参数作为double
传递,并且在printf()时
运行并看到%d
,它会将其解释为int
,当它错误地解释位模式时(在本例中,可能是参数的大小,也可能是参数后面的任何其他参数),事情就会开始出大问题
这就是为什么这些函数在C语言中很少需要对void*
进行强制转换的原因之一,因为指向不同类型对象的指针可以有不同的大小,而且%p
需要一个void*
,所以必须传递给它一个void*
,而不是一个po与任何其他对象类型关联
不过,请注意,现代编译器可以是智能的,而且它们知道标准C函数是如何工作的,因此它们只需了解函数的标准行为,如printf()
,这样他们就可以对类似这样的不匹配的参数类型发出警告,尽管他们实际上不会为您解决这些问题。更详细地解释一下,这是因为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;
}
编译器在运行并理解格式字符串中的%d
之前,不知道需要什么类型的printf()
。因此,它所能做的就是将double
参数作为double
传递,并且在printf()时
运行并看到%d
,它会将其解释为int
,当它错误地解释位模式时(在本例中,可能是参数的大小,也可能是参数后面的任何其他参数),事情就会开始出大问题
这就是为什么这些函数在C语言中很少需要对void*
进行强制转换的原因之一,因为指向不同类型对象的指针可以有不同的大小,而且%p
需要一个void*
,所以必须传递给它一个void*
,而不是一个po与任何其他对象类型关联
但是,请注意,现代编译器可以是智能的,并且它们知道标准C函数是如何工作的,因此它们可以被告知函数的标准行为,例如printf()
,这样它们就可以向您发出关于不匹配的警告