为内联函数定义了多次,有多大可能? 《C++入门书》下面的引语使我困惑了很多。

为内联函数定义了多次,有多大可能? 《C++入门书》下面的引语使我困惑了很多。,c++,compiler-errors,linker,inline,C++,Compiler Errors,Linker,Inline,与其他函数不同,可以定义内联函数和constexpr函数 在程序中执行多次。毕竟,编译器需要 定义,而不仅仅是声明,以便扩展代码。 但是,给定inline或constexpr的所有定义都必须 完全匹配。因此,inline和constexpr功能正常 在标题中定义。 -C++引物第五ED,240 pp “可能在程序中多次定义”这句话让我很困惑。据我所知,声明可以多次进行,但定义只需要一次 有人能给我举个例子说明为什么有多重定义。在头文件中(我们称之为foo.h),您可以 inline int fo

与其他函数不同,可以定义内联函数和constexpr函数 在程序中执行多次。毕竟,编译器需要 定义,而不仅仅是声明,以便扩展代码。 但是,给定inline或constexpr的所有定义都必须 完全匹配。因此,inline和constexpr功能正常 在标题中定义。 -C++引物第五ED,240 pp

“可能在程序中多次定义”这句话让我很困惑。据我所知,声明可以多次进行,但定义只需要一次

有人能给我举个例子说明为什么有多重定义。

在头文件中(我们称之为
foo.h
),您可以

inline int foo() { /* do stuff */ }
现在,如果在两个cpp文件中包含
foo.h
,那么
foo
将在每个文件中定义,这将是一个多定义错误。由于
foo
被标记为
inline
,这是可以的,因为所有的定义都是相同的

据我所知,声明可以多次进行,但定义只需要一次


编译器在翻译单元(基本上是一个cpp文件)上工作,在其中,它可以进行各种优化,但函数内联和
constexpr
要求编译器知道函数的定义。这意味着每个翻译单元都需要定义其中的函数。我们使用内联来解决这个问题,否则它将是一个多定义错误。

我认为问题在于,我们可以用“定义”来表示多个方面。当您在头文件中编写内联函数时,它只“定义”了一次,因为在源代码中只有一个函数具有该名称

但这不是编译器和链接器看待世界的方式。如果在从
a.cpp
b.cpp
调用的头文件中有一个内联函数
foo
,则该函数的完整编译版本将包含在
a.obj
b.obj
中。链接器通过只选择其中一个编译版本包含在最终二进制文件中来解决这个问题


请注意,我在这里忽略了重要的细节,但这是总体思路(我认为你的教科书没有提到这点)。

举个例子。此版本无效

// main.cpp
inline int square(int num) {
    return num * num;
}

inline int square(int num) {
    return num * num;
}

int main()
{
    return square(2);
}

但当你把它放在多个
.cpp
文件(又名.translation units)中时就没问题了,因为现在链接器的任务就是做正确的事情

// b.cpp
inline int square(int num) {
    return num * num;
}

// main.cpp
inline int square(int num) {
    return num * num;
}

int main()
{
    return square(2);
}
构建:
gcc main.cpp b.cpp
同样的方法也适用于
#include
它将把代码放在那些
.cpp
文件中,仅此而已

当然,如果函数体是内联的,那么就不需要链接,所以没有问题:)

如果编译器决定执行一个离线版本,那么最终会有多个对象文件(
.o
)具有相同“内联”函数的定义。这样的定义将被标记

多亏了这个标记链接器,它不会给出已经找到多个定义的结果,而只会选择它找到的第一个定义

所以,如果所有的定义都是相同的,那就好了!如果我们有不同的功能主体,我们就会陷入麻烦。文件
b.cpp

// b.cpp
inline int square(int num) {
    return 1;
}

同一内联函数具有多个不同定义是未定义的行为。它当然会编译,但我们得到了什么?这取决于链接器的选择:D

这就是
inline
(和
constexpr
,这意味着
inline
)函数的特殊性:它们可以有几个定义。相关问题: