C语言 函数定义是否存在于头文件中?

hc2pp10m  于 2023-08-03  发布在  其他
关注(0)|答案(2)|浏览(107)

在C/C++中,函数定义存在于头文件中还是仅存在于声明中?以math.h中的函数pow()为例。如果函数的定义没有出现在头文件中,那么头文件包含什么,以便函数定义被正确链接?

acruukt9

acruukt91#

简短回答:* 看情况 *
长长的回答:* 看情况 *
第一个问题:什么是函数定义?*
在C++中,一个函数既可以 * 声明 *,也可以 * 定义 *。
一个声明的函数看起来像这样:

// <cmath>

namespace std {
    double pow(double base, double exp);
}

字符串
而一个定义的看起来像这样:

#include <cmath>

double std::pow(double base, double exp) {
    // Do stuff...
}


不同之处在于,定义的函数具有一个代码块(由大括号{...}表示)。因此,声明和定义之间的区别在于,定义以函数的底层代码为特征,而声明则没有任何代码。
但是假设它只声明了,编译器怎么知道函数的位置呢?
通常,C是在不同的 * 翻译单元 * 中编译的(阅读:每个翻译单元包括一个公共头文件(这里是<cmath>),它提供了它的函数的声明(这里是::std::pow)。
其中一个单元还包含::std::powdefinition。当这些单元-以对象文件或库(单元的集合)的形式-由 * 链接器 * 放置在一起时,函数的所有使用都将调用位于定义它的单元中的适当代码。如果定义函数的单元没有被链接,链接器将报错。
请注意,只能有一个定义。如果多个单元有自己的::std::pow定义,链接器将再次由于多个定义而抱怨。
然而,这个“一个定义规则”并不普遍,它的例外是:
1.inline 函数(由inline存储类说明符表示),可以在多个单元中定义,但最终会丢弃除一个定义外的所有定义。这还包括 constexprconsteval(immediate)函数,这两个函数都是隐式内联的。
1.static 函数(由static存储类说明符表示),其位于其转换单元的本地;它们不与来自其它单元的符号冲突-即使它们共享相同的标识符。
::std::pow的情况实际上相当复杂。通常,它会被外部定义。然而,从C
26开始,它必须是一个 constexpr 函数,所有这些函数都是内联的 * 根据定义 *(参见cppreference)。
标准库中的许多其他函数也是如此。它们中的许多是在外部定义的(在另一个翻译单元中,如::std::exit),但也有许多是在各自的头文件中定义的(如::std::is_constant_evaluated)。在其他情况下,外部函数在后来的标准版本中被内联(如::std::pow)。
总之,::std::pow可能在<cmath>头中定义…而它也可能不是。这取决于标准的实施和版本。
但一般情况是,是的,函数是在声明它们的头文件之外定义的(在另一个翻译单元中)。

rks48beu

rks48beu2#

头文件只是由预处理器包含在编译单元中的源文件。从技术上讲,它们可以包含任何C或C代码,但在实践中,它们用于公开编译单元之间的定义/声明,同时隐藏实现细节。
在C语言中,同一个外部对象/函数不能有两个定义,所以头文件通常只包含函数声明或变量定义。
在C
中,有一个类似的规则:一个定义规则。但是也有一些例外,比如模板定义、类成员定义和带有inline说明符的函数。但是它们的定义必须在所有翻译单元中匹配,否则行为是未定义的。
pow的情况下,程序可以访问它,因为编译器默认链接libc。

相关问题