【问题标题】:extern inline function was referenced but not defined引用了外部内联函数但未定义
【发布时间】:2016-11-23 13:52:24
【问题描述】:

我有一个希望内联的函数(我们称之为 void foo(void) {})。但我在 .cpp 文件中定义了它。
我无法将该函数移动到标题,因为它正在使用 .cpp 中的其他函数。



编辑:
下面的代码就像真正的代码一样没有使用 c++ 功能。我可以清楚地补充:

#ifdef __cplusplus
extern "C"
#endif

如果我想将下面的代码转换为 c99,我只需要更改我的项目属性(或 makefile,如果你愿意)不是代码。我也在询问 c++,因为它可以解决我的问题,而 c99 不能。
因此,我的问题中的 C 和 C++ 标记是合理的。代码是可移植的
见:When to use extern "C" in C++?



编辑 #2
好的,我知道我必须将 foo() 定义放在头文件中。如何在不将它们移动到头文件的情况下从foo() 调用func_a()func_b()?有什么解决办法吗?



示例
file.c / .cpp:

int    func_a (int a,    int b,    int c)    {/*...*/};
double func_b (double a, double b, double c) {/*...*/};

void   foo    (int a, double b) { // unction definition
    //...
    int myInt = func_a(a, 2, 3);
    //...
    double myDouble = func_b(1.5f, b, 3.5f);
    //...
}

文件.h:

// Something before.

void foo (int a, double b); // function declaration

// Something after.



我想指出:

  • 我正在使用 Visual Studio 2015。
  • 我正在编写比较大的项目(~ 7000 行代码)。它是物理系统的模拟。
  • file.h 包含在许多其他编译单元中。
  • foo(int, double) 很小,它从file.cpp 调用其他函数
  • 出于优化原因,我想将foo(int, double) 内联(我最终将使用__forceinline__
  • 我在我的程序中多次调用foo()。它还用于几个 while 循环(每个循环 100k + 次迭代),因此让这个符号 foo() 不是内联是很广泛的。
  • 我厌倦了只有标题的库。



我尝试:
file.c / .cpp:

extern inline
void   foo    (int a, double b) {\*...*\}; // Definition

文件.h:

extern inline
void   foo    (int a, double b); // Declaration

但我不断收到警告:

warning : extern inline function "foo" was referenced but not defined

我不明白为什么会收到此警告。



有什么办法:

  • 在我的 .cpp 文件中保留foo() 的定义?但仍使其内联
  • foo() 移动到file.h,将func_a()func_b() 保留在file.cpp 中,但使func_a()func_b() 符号对foo()“可见”(!并且仅对foo() !) 来自file.cpp
  • 还有其他解决方法吗?


抱歉,我仍在学习 cpp,我不知道我的问题是否清楚,或者是否可以从 .cpp 文件中内联函数。

【问题讨论】:

  • C is not C++ is not C. 不要添加无关标签!
  • @olaf 如您所见,我没有使用 c++ 功能。 extern "C" 是我在代码中经常使用的东西。 foo() 很可能最终也会使用它。我说的是c++,因为c++可以解决这个问题而c不能
  • 内联函数的定义必须存在于访问它的翻译单元中
  • 顺便说一句,您可以将func_a func_b 放入一些(可能是嵌套的)命名空间中,这样当前的命名空间就不会具有这两个功能。
  • [basic.def.odr] 说(第 4 段)“内联函数应在其奇数使用的每个翻译单元中定义。”您不能在一个翻译单元中使用它,而是在另一个翻译单元中定义它。

标签: c++ c inline extern


【解决方案1】:

在 C++ 中,inline 关键字的含义如下:

  • 函数的主体必须出现在每个使用该函数的源文件中。
  • 所有源文件中的函数“主体”必须逐个令牌和逐个实体相同。
  • 编译器和链接器必须确保它们对具有这些“多体”的函数没有问题

这就是它所做的一切。在实践中,这意味着它能够并强制您将函数体放入头文件中。

关键字本身与函数内联无关。只是如果编译器想要能够内联函数体,它必须在编译调用代码时可以访问它;换句话说,函数的主体必须在同一个源文件中,或者在该源文件包含的头文件中。

如果你想让编译器在所有调用点中内联函数,并且这些调用点发生在多个源文件中,你必须将函数放入头文件中(并且标记为inline)。

另一方面,链接器也可以进行内联,称为链接时代码生成或整个程序优化或类似的东西(取决于您的工具链的供应商)。启用此功能将

  1. 延长构建时间,并且
  2. 允许链接器将函数内联到调用站点跨源文件

所以要内联函数,您有两个选择。要么将函数放入头文件,要么启用并依赖链接时优化来为您内联它。


在您的特定情况下,要使用__forceinline__,您将在头文件中定义foo。这需要foo 的定义才能看到func_afunc_b 的声明。为了防止命名空间污染,可以在foo范围内声明这些函数:

inline void foo(int a, double b) { // function definition
    int func_a(int, int, int);
    double func_b(double, double, double);

    //...
    int myInt = func_a(a, 2, 3);
    //...
    double myDouble = func_b(1.5f, b, 3.5f);
    //...
}

【讨论】:

  • 非常感谢。我希望我可以将函数定义留在 src 文件中。因此,有什么方法可以使 src 文件中的 foo() 可以看到 func_a()func_b() 吗?顺便说一句,这段代码将以__forceinline__ 而不是inline 关键字结尾,所以我将能够强制我的编译器在任何地方内联它。
  • @cukier9a7b5 你能简单地在头文件中声明(而不是定义)函数吗?
  • 我最终将使用仅标题库。我不喜欢它。此外,我将声明许多符号,我不会为此使用它们,它们不应该在 file.cpp 之外可见,我在这里考虑的是代码 - 封装。
猜你喜欢
  • 1970-01-01
  • 2012-03-13
  • 2021-10-28
  • 2013-10-04
  • 2023-02-14
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
  • 2014-10-07
相关资源
最近更新 更多