首先,您必须了解C99内联模型——也许您的头有问题。对于具有外部(非静态)链接的内联函数,有两种定义
-
外部定义
一个函数的这个定义在整个程序中只能出现一次,在一个指定的tu中。它提供了一个可以从其他tus中使用的导出函数。
-
内联定义
这些出现在每个被声明为单独定义的时间单位中。定义是这样的
不
需要彼此相同或与外部定义相同。如果在库中内部使用,它们可以省略对函数参数的检查,否则将在外部定义中进行检查。
函数的每个定义都有自己的局部静态变量
,因为它们的本地声明没有链接(它们不象C++一样共享)。非静态内联函数的定义将是内联定义,如果
-
tu中的每个函数声明都包含说明符
inline
和
-
tu中没有包含说明符的函数声明
extern
.
否则,必须出现在该tu中的定义(因为内联函数必须在声明的同一tu中定义)是外部定义。在对内联函数的调用中
未指定是使用外部定义还是使用内联定义
.但是,因为在所有情况下定义的函数都是相同的(因为它有外部链接),所以在所有情况下,它的地址都是相等的,不管出现多少内联定义。因此,如果采用函数的地址,编译器很可能会解析为外部定义(尤其是禁用优化时)。
演示错误使用
内联的
,因为它在两个tus中包含两次函数的外部定义,从而导致多个定义错误
// included into two TUs
void f(void); // no inline specifier
inline void f(void) { }
以下程序是危险的,因为编译器可以自由使用外部定义,但程序不提供外部定义
// main.c, only TU of the program
inline void g(void) {
printf("inline definition\n");
}
int main(void) {
g(); // could use external definition!
}
我使用GCC做了一些测试案例,进一步演示了这种机制:
主C
#include <stdio.h>
inline void f(void);
// inline definition of 'f'
inline void f(void) {
printf("inline def main.c\n");
}
// defined in TU of second inline definition
void g(void);
// defined in TU of external definition
void h(void);
int main(void) {
// unspecified whether external definition is used!
f();
g();
h();
// will probably use external definition. But since we won't compare
// the address taken, the compiler can still use the inline definition.
// To prevent it, i tried and succeeded using "volatile".
void (*volatile fp)() = &f;
fp();
return 0;
}
MIN 1.C
#include <stdio.h>
inline void f(void);
// inline definition of 'f'
inline void f(void) {
printf("inline def main1.c\n");
}
void g(void) {
f();
}
MIN 2.C
#include <stdio.h>
// external definition!
extern inline void f(void);
inline void f(void) {
printf("external def\n");
}
void h(void) {
f(); // calls external def
}
现在,程序输出我们期望的结果!
$ gcc -std=c99 -O2 main.c main1.c main2.c
inline def main.c
inline def main1.c
external def
external def
查看符号表,我们将看到内联定义的符号没有导出(从
main1.o
,同时导出外部定义(从
main2.o
)
现在,如果静态库中每个库都有其内联函数的外部定义(正如它们应该的那样),那么它们自然会相互冲突。解决方案是使内联函数成为静态的,或者只是重命名它们。它们总是提供外部定义(因此它们是完全成熟的定义),但它们不会被导出,因为它们具有内部链接,因此不会相互冲突。
static inline void f(void) {
printf("i'm unique in every TU\n");
}