以下代码的含义是什么?

时间:2016-09-29 22:43:40

标签: c gcc compilation execute

  

我在一次采访中遇到了这个问题,该男子问我,如果我编译并执行以下代码,结果是什么,以及为什么。我很好奇这个问题而且我没有真正得到它。

     

当我输入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;
}

3 个答案:

答案 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)

相关问题