当我传入一个非零值作为参数时,为什么这个函数打印0?

时间:2016-10-06 21:53:21

标签: c function function-prototypes

这里的代码:

#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?

4 个答案:

答案 0 :(得分:7)

在您编写的程序中,您尚未调用test函数,而无需先对其进行原型设计。现代编译器通常会拒绝这一点,但是对于较旧的编译器 - 或者提供旧C代码支持的编译器 - 程序将隐式地尝试推断出参数类型。您已提供7.44作为参数,这意味着编译器希望您将传递doubleint,因为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()函数的原型。