从另一个CPP文件调用C++内联函数

3

我正在尝试了解一些有关extern、static等基本概念的知识,并尝试了以下示例,但我不明白为什么我不能调用函数“just”,因为它可能是内联的。

我的第一个文件:F1.cpp

 #include <iostream>
 
 void Modify();
 int i;

 int main() {
      i = 1;

      std::cout << "i = " << i << std::endl;
      Modify();
      std::cout << "i = " << i << std::endl;
 
      return 0;
 }

第二个文件:F2.cpp
#include <iostream>

extern int i;

inline void Modify() {
    i = 99;

    std::cout << "i = " << i << std::endl;

}

在F2.cpp中使用inline关键字后,我在F1.cpp文件中得到了一个未定义的Modify()引用错误。移除后,代码编译并正常工作。
我认为C++中的inline关键字类似于static关键字?
我也看过这个主题,但除了文档说内联函数应该始终位于头文件中之外,我不理解:C++ inline member function in .cpp file 感谢您的帮助!

@MikeSeymour:感谢您的纠正!我刚学到了新东西。 - Cornstalks
标准规定:内联函数应该在使用它的每个翻译单元中定义。 - n. m.
4个回答

6
我认为C++中的inline关键字具有类似于static关键字的行为,但是有所不同。名称仍然具有外部链接性,并且程序的行为就像只有一个定义(例如,该函数在任何地方都具有相同的地址,而任何静态变量的实例仅有一个)。inline的效果如下:
- 该函数可以在多个翻译单元中定义,只要所有定义都相同。普通函数只能定义一次。 - 必须在使用该函数的任何翻译单元中定义该函数。这使得编译器可以省略非内联定义(如果不需要)。
您的代码违反了第二条规则,这可能会导致链接错误。这就是为什么内联函数通常需要在头文件中,如果需要在多个单元中使用它们。

我不是很理解第二点中的部分,即“如果不需要非内联定义,则允许编译器省略它”。这是否与编译器选择是否应该进行内联有关? - Jonathan Taws
1
@Hawknight:是的;如果它将每个对函数的调用都内联,并且您不执行任何需要非内联定义的操作(例如获取其地址),那么就没有必要浪费时间和空间生成一个。 - Mike Seymour

5
根据C++标准(7.1.2函数说明符):
4.…如果一个具有外部链接的函数在一个翻译单元中声明为内联函数,则在其出现的所有翻译单元中都必须将其声明为内联函数;不需要进行诊断。
并且
4 内联函数应在其被odr使用的每个翻译单元中定义,并且在所有情况下均应具有完全相同的定义。
在C语言中( C标准的6.7.4函数说明符部分 ),外部函数的内联说明符具有不同的语义:
7.…内联定义不提供函数的外部定义,也不禁止在另一个翻译单元中存在外部定义。内联定义提供了对于同一翻译单元中的任何调用都可由翻译器使用的替代方案。调用函数时使用内联定义还是外部定义是未指定的。

我接受了你的答案,尽管其他答案也是正确且解释得很好。我会按照投票数来决定 :) - Jonathan Taws

2
是的,inline的意思与static相似。标准(§[basic.def.odr]/3)中的具体要求是:

内联函数必须在使用它的每个翻译单元中定义。

在这种情况下,您已经在一个翻译单元中定义了inline函数,但在另一个翻译单元中只声明了它,因此您没有满足上面所述的在使用它的TU中定义的要求。
内联函数仍然可以具有外部链接。当您这样做时,标准保证它会产生一个在整个程序中具有相同地址的单一函数。
以防不清楚:翻译单元基本上是一个源文件,在预处理之后,它包括直接在该源文件中的所有内容以及它包含的头文件中的所有内容,减去由于#ifdef#if等而跳过的任何内容。

谢谢澄清,我现在明白了!关于内联的外部链接,你怎么做呢? - Jonathan Taws
1
@Hawknight:默认情况下,该名称具有外部链接,但您仍然必须在每个TU中定义它。基本上,外部链接意味着如果编译器决定不在线扩展定义,则它将始终生成一个(且仅一个)离线定义,因此任何未在线扩展的调用都将是对该定义的调用。 - Jerry Coffin

1
当你声明一个函数为inline时,只有定义它的翻译单元(在这个例子中是F2.cpp)才能访问该函数。如果你将它放在头文件中(比如F.h),并在F1.cpp和F2.cpp中都#include "F.h",那么inline函数会在每个翻译单元中被定义一次。通常,这会导致链接器错误,但由于你声明了函数为inline,所以链接器不知道你的Modify()函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接