【问题标题】:what does the following code means? [closed]以下代码是什么意思? [关闭]
【发布时间】:2016-09-29 22:43:39
【问题描述】:

我在一次采访中遇到了这个问题,那个人问我如果我编译并执行下面的代码,结果是什么,为什么。我对这个问题很好奇,但我并没有真正明白。

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

【问题讨论】:

  • 您期望得到什么答案?此外,在“编辑”之前,“extern”没有被注释……那个版本给你预期的输出了吗???最后,注释掉“extern”后,我从“gcc”收到一条警告消息,你收到了吗???
  • YouTube 上还有很多关于 C、方法、函数和变量声明的好资源。坚持下去,祝你找工作好运!
  • @BasicIsaac:避免引用“方法”的资源; C 没有它们。 (C++ 成员函数有时也称为“方法”,但严格来说也不正确。)
  • @KeithThompson 感谢您的提醒。我点击了 C# 标签,不知何故来到了这里。我不明白这个问题有多少反对票,如果没有 get_val() 引用,该函数会返回一个大数字,这真的很奇怪。
  • @BasicIsaac:没那么奇怪;看我的回答。

标签: c gcc compilation execute


【解决方案1】:

f2.c 中,在更改之前,没有get_val 的声明。因此默认情况下,它假定该函数返回一个int。因为这与函数的实际返回类型不匹配,所以这会导致 undefined behavior

添加声明时,函数的正确返回类型是已知的,因此代码按预期工作。

【讨论】:

  • 未声明函数返回 int 的假设仅适用于 1999 ISO C 标准 (C99) 之前,该标准删除了“隐式 int”规则。在 C99 或更高版本中,调用未声明的函数是违反约束的,需要编译时诊断。一旦发出诊断,如果它不是致命的,则程序的后续行为是未定义的,但编译器可以完全拒绝它。
  • @KeithThompson 尽管如此,编译器的常见行为(即使在 C99 模式下)是发出诊断信息,然后继续使用 C89 行为
  • @M.M:不幸的是真的。
【解决方案2】:

我试图看看你是如何得到 1717986918 的结果,但我不知道。在你描述的两种方式中,我得到了一个 5 打印。这就是为什么:

  • 你正在“解析”你的函数的双精度值返回一个 int 类型(但是

    int a = get_val();
    
  • 之后,您将以小数的格式打印它

    printf("%d\n", a);
    

【讨论】:

    【解决方案3】:

    您正在调用 get_val() 函数,但没有可见的声明。

    不要那样做。从 C99 开始,该语言禁止(见下文)对没有可见声明的函数进行任何调用。 (该声明应该是一个原型,它指定参数的类型,但这不是必需的。)

    在 C99 之前(删除了“隐式 int”规则),对未声明函数的调用将要求编译器假定该函数返回 int 类型的结果,并且它期望调用实际传递的参数的数量和类型。如果实际函数定义违反了该假设,因为get_val() 返回double 结果,则行为未定义。

    (通过“禁止”,我的意思是这样的调用是一个约束违反。这意味着一个符合要求的编译器必须诊断它,但不需要拒绝它。许多编译器仍然允许调用未声明的函数,通常带有非致命警告,并实现了 C99 之前的语义。因此编译器可能会让你侥幸逃脱。不要。)

    所以发生的情况是 get_val() 被调用,它返回一个带有值 5.6double 结果——但调用者期待一个 int 结果,所以它在 @987654330 中存储了一些未定义的垃圾值@。

    您看到的值1717986918 恰好是十六进制的0x66666666。在 IEEE 浮点中,至少在我的系统上,值 5.6 表示为 0x6666666666661640。显然,存储的值恰好是double 值的前半部分(很可能double 是8 个字节,int 是4 个字节)。

    这解释了你所看到的行为,但你不应该指望它。

    永远不要在没有可见声明的情况下调用函数。

    获取在另一个源文件中定义的函数的可见声明的常用方法是#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)。这指定该函数不接受任何参数,而不是未指定数量的参数。不同之处在于,使用double get_val(),如果调用不正确,编译器(可能)不会抱怨,例如get_val("foo")

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-20
      • 2014-05-26
      • 1970-01-01
      • 1970-01-01
      • 2012-05-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多