这里的代码:
#include <stdio.h>
int main(void) {
test(7.4, 4);
return 0;
}
void test(float height, float radius){
printf("%f", height);
}
将打印:
0.000000
这是为什么?为什么不打印7.4?
答案 0 :(得分:7)
在您编写的程序中,您尚未调用test
函数,而无需先对其进行原型设计。现代编译器通常会拒绝这一点,但是对于较旧的编译器 - 或者提供旧C代码支持的编译器 - 程序将隐式地尝试推断出参数类型。您已提供7.4
和4
作为参数,这意味着编译器希望您将传递double
和int
,因为7.4
是一个double
字面值,因此它会生成代码以将第一个参数作为double
传递,将第二个参数作为int
传递。
稍后,当您实际定义test
时,您指定参数为float
s,这与先前的代码不匹配。结果,该函数尝试读取它的第一个参数,好像它是一个float
,因此它最终以某种方式重新解释一些字节,恰好将它们解释为一个浮点数。接近负零。
要解决这个问题,可以在调用test
函数之前对其进行原型化,或者在使用之前对其进行定义。请注意,带有警告的编译器会明确地告诉您隐式声明和定义不匹配:
nodecl.c: In function ‘main’:
nodecl.c:4:3: warning: implicit declaration of function ‘test’ [-Wimplicit-function-declaration]
test(7.4, 4);
^
nodecl.c: At top level:
nodecl.c:8:6: warning: conflicting types for ‘test’
void test(float height, float radius){
^
nodecl.c:4:3: note: previous implicit declaration of ‘test’ was here
test(7.4, 4);
^
展望未来,如果您看到这些警告,您现在就知道他们正在谈论什么,您应该能够更快地诊断错误。
答案 1 :(得分:2)
在使用gcc的Linux下,会发生这种情况:编译器将7.4
传递为double,因为test
原型仅在main之后定义。
0000000000400506 <main>:
400506: 55 push %rbp
400507: 48 89 e5 mov %rsp,%rbp
40050a: 48 83 ec 10 sub $0x10,%rsp
40050e: 48 b8 9a 99 99 99 99 movabs $0x401d99999999999a,%rax
400515: 99 1d 40
400518: bf 04 00 00 00 mov $0x4,%edi
40051d: 48 89 45 f8 mov %rax,-0x8(%rbp)
400521: f2 0f 10 45 f8 movsd -0x8(%rbp),%xmm0
400526: b8 01 00 00 00 mov $0x1,%eax
40052b: e8 07 00 00 00 callq 400537 <test>
400530: b8 00 00 00 00 mov $0x0,%eax
400535: c9 leaveq
400536: c3 retq
0x401d99999999999a
是你的64位加倍,即7.4。 test
函数将该值解释为单个精度数字(浮点数,如原型中指定的),使用printf
(浮点数到双转换)通过{{1}将其传递给cvtss2sd
}}:
xmm0
这导致只有初始64位值的一小部分被转换为实际的双重打印到stdout,即0x9999999a,结果接近0结果。
答案 2 :(得分:1)
打开编译器警告 - 并修复它所警告的内容。
使用test()
函数的函数原型。
答案 3 :(得分:0)
我在GGC编译器中编译了你的程序,我收到了以下错误
float.c:11:6: warning: conflicting types for ‘test’ [enabled by default]
void test(float height, float radius)
^
float.c:7:5: note: previous implicit declaration of ‘test’ was here
test(7.4, 4);
^
然后我添加了test()
函数befor main()函数的原型,如
void test(float, float);
然后再次编译,我得到了正确的输出。所以,添加test()
函数的原型。