我在一次采访中遇到了这个问题,该男子问我,如果我编译并执行以下代码,结果是什么,以及为什么。我很好奇这个问题而且我没有真正得到它。
当我输入
gcc f1.c f2.c
然后./a.out
时,它会在我的x64 PC中输出一个奇怪的数字:1717986918
,然后我在f2.c中添加一行:extern double get_val( );它输出5。
在f1.c:
double get_val()
{
return 5.6;
}
f2.c:
#include<stdio.h>
//extern double get_val();
int main()
{
int a=get_val();
printf("%d\n", a);
return 0;
}
答案 0 :(得分:1)
在f2.c
中,在更改之前,get_val
没有声明。因此,默认情况下,该函数返回int
。因为这与函数的实际返回类型不匹配,所以会产生undefined behavior。
添加声明时,函数的正确返回类型是已知的,因此代码按预期工作。
答案 1 :(得分:0)
我试着看看你如何得到1717986918的结果,但我无法弄明白。在你描述的两种方式中,我得到了5个印刷品。这就是原因:
你正在解析&#34;函数的double值返回whitin int类型(但
int a = get_val();
之后,您将以十进制格式打印
printf("%d\n", a);
答案 2 :(得分:0)
您正在调用get_val()
函数而没有可见的声明。
不要那样做。从C99开始,语言禁止(见下文)对没有可见声明的函数的任何调用。 (该声明应该是一个原型,它指定参数的类型,但这不是必需的。)
在C99(删除了“隐式int
”规则)之前,对未声明函数的调用将要求编译器假设该函数返回类型{{的结果1}},并且它期望调用实际传递的参数的数量和类型。如果实际函数定义违反了该假设,那么因为int
返回get_val()
结果,所以行为是未定义的。
(通过“禁止”,我的意思是这样的调用是约束违规。这意味着符合标准的编译器必须对其进行诊断,但不要求拒绝它。许多编译器仍允许调用未声明的函数,通常带有非致命的警告,并实现C99之前的语义。因此编译器可能会让你逃脱它。不要。)
所以会发生double
被调用,它会返回值为get_val()
的{{1}}结果 - 但是调用者期望double
结果,所以它在5.6
中存储一些未定义的垃圾值。
您看到的值int
恰好是十六进制的a
。在IEEE浮点中,至少在我的系统上,值1717986918
表示为0x66666666
。显然,存储的值恰好是5.6
值的前半部分(很可能0x6666666666661640
是8个字节而double
是4个字节)。
这样就解释了你所看到的行为,但你应该不指望它。
永远不要在没有可见声明的情况下调用函数。
获取另一个源文件中定义的函数的可见声明的常用方法是double
正确的标题。
以下是正确方法的示例:
int
:
#include
f1.h
:
#ifndef F1_H
#define F1_H
extern double get_val(void);
#endif
f1.c
:
#include "f1.h"
double get_val(void)
{
return 5.6;
}
请注意,我已在所有函数声明和定义中将f2.c
更改为#include <stdio.h>
#include "f1.h"
int main(void) {
int a = get_val();
printf("%d\n", a);
return 0;
}
。这指定该函数不带参数,而不是未指定数量的参数。区别在于()
,如果您错误地调用它,编译器(可能)不会抱怨,例如(void)
。