【发布时间】:2020-11-28 15:03:14
【问题描述】:
我在 .c 中定义了我的函数(没有头声明),如下所示:
inline int func(int i) {
return i+1;
}
然后在下面的同一个文件中我使用它:
...
i = func(i);
在链接过程中,我得到了“对 'func' 的未定义引用”。为什么?
【问题讨论】:
-
要么设为
static,要么提供链接器可以找到的非内联定义。
我在 .c 中定义了我的函数(没有头声明),如下所示:
inline int func(int i) {
return i+1;
}
然后在下面的同一个文件中我使用它:
...
i = func(i);
在链接过程中,我得到了“对 'func' 的未定义引用”。为什么?
【问题讨论】:
static,要么提供链接器可以找到的非内联定义。
这是因为 GCC 处理内联函数的方式。 GCC 执行内联替换作为优化的一部分。
要消除此错误,请在内联之前使用static。使用static关键字强制编译器内联该函数,使程序编译成功。
static inline int func(int i) {
return i+1;
}
...
i = func(i);
【讨论】:
inline 的含义在 C 和 C++ 之间有所不同。
static 和inline 由于某种原因是正交的。如,static 暗示它必须存在,而inline(根据定义)不存在。 (“不存在”是指定义的符号,因为它会被内联)。
C99 中的inline 模型与大多数人想象的有点不同,尤其是与 C++ 使用的模型不同
inline 只是一个提示,以便编译器不会抱怨双重定义的符号。如果需要,它不能保证函数是内联的,也不能保证生成符号。要强制生成符号,您必须在inline 定义之后添加一种实例化:
int func(int i);
通常你会在头文件中定义inline,然后将其包含在几个 .c 文件(编译单元)中。而且您只会在其中一个编译单元中拥有上述行。您可能只看到您遇到的问题,因为您没有对编译器运行进行优化。
因此,您在 .c 文件中包含 inline 的用例没有多大意义,最好只使用 static,即使是额外的 inline 也不能给您带来太多收益。
【讨论】:
inline 的extern 文件范围声明确实强制定义不是内联的
-O0 编译时,我想你的意思是,gcc 通常不会内联任何函数。那么你必须在某处定义了符号,否则它不会找到任何inline declare-defined 函数。
C99 内联语义经常被误解。 inline 说明符有两个用途:
首先,作为static inline 和extern inline 声明的编译器提示。如果删除说明符,语义保持不变。
其次,在原始inline(即没有static 或extern)的情况下,提供内联定义作为外部定义的替代,外部定义必须存在于不同的翻译单元中。不提供外部是未定义的行为,通常表现为链接失败。
如果您想将一个函数放入一个共享库中,这将特别有用,同时也让函数体可用于优化(例如内联或特化)。假设一个足够聪明的编译器,这可以让您恢复 C++ 模板的许多优点,而无需跳过预处理程序。
请注意,它比我在这里描述的要混乱一些,因为有另一个文件范围非内联外部声明将触发 Jens 的回答中描述的第一种情况,即使定义本身是 inline 而不是 extern inline .这是设计使然,因此您可以在头文件中拥有一个内联定义,您可以通过为外部声明添加一行来将其包含到提供外部定义的源文件中。
【讨论】: