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()
,这样它们就可以向您发出关于不匹配的警告