隐式函数声明和链接

Edg*_*jān 4 c linkage function-declaration implicit-declaration

最近我学会了C中的隐式函数声明.主要观点很明确,但我对在这种情况下理解链接过程有些麻烦.

请考虑以下代码(文件ac):

#include <stdio.h>

int main() {
    double someValue = f();
    printf("%f\n", someValue);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果我尝试编译它:

gcc -c a.c -std=c99
Run Code Online (Sandbox Code Playgroud)

我看到关于隐式声明功能的警告f().

如果我尝试编译和链接:

gcc a.c -std=c99
Run Code Online (Sandbox Code Playgroud)

我有一个未定义的引用错误.一切都很好.

然后我添加另一个文件(文件bc):

double f(double x) {
    return x;
}
Run Code Online (Sandbox Code Playgroud)

并调用下一个命令:

gcc a.c b.c -std=c99
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,一切都成功连接 当然在./a.out调用后我看到了垃圾输出.

所以,我的问题是:如何将隐式声明函数的程序链接起来?在编译器/链接器的引擎下我的例子会发生什么?

我读了那么像一些专题的这个,这个这个,但还是有问题.

Sou*_*osh 5

首先,因为C99,从标准中删除了函数的隐式声明.编译器可能支持编译遗留代码,但这并不是强制性的.引用标准前言,

  • 删除隐式函数声明

这就是说,按照C11章节§6.5.2.2

如果使用不包含原型的类型定义函数,并且促销后的参数类型与促销后的参数类型不兼容,则行为未定义.

所以,在你的情况下,

  • 函数调用本身是隐式声明(从C99开始变为非标准),

  • 并且由于函数签名不匹配[ 假定函数的隐式声明具有int返回类型 ],您的代码将调用未定义的行为.

只是为了添加更多的引用,如果在调用尝试在同一个编译单元中定义函数,由于不匹配签名,您将收到编译错误.

但是,您的函数是在单独的编译单元中定义的(并且缺少原型声明),编译器无法检查签名.编译之后,链接器获取目标文件,并且由于链接器中没有任何类型检查(并且目标文件中也没有信息),请愉快地链接它们.最后,它将成功完成编译和链接以及 UB.