C99版的C语言引入了inline关键字开始支持inline 函数,在这之前传统的C语言(C89)是没有inline 关键字的,也不支持inline 函数。不过大多数 C89 的编译器都将inline作为一种附加特性早早的就加进去了。gcc 也不例外,不过gcc增加inline特性时C99还没定型,gcc中inline 的语意与C99也有些许的区别。这里就主要说说gcc 中的inline 特性。
另外,本文只讨论C语言,C++标准中很早就支持inline,不过inline的语意C和C++ 是有细微差别的。
先举一个最简单的例子:
//main.c #include <stdio.h> int foo(void); int main() { int a = foo(); printf("a = %d", a); return 0; } //foo.c inline int inline_func(int a) { return a + 1; } int foo(void) { int x = 5; x = inline_func(x); return x; }
这个是inline 最简单的用法,无论是gcc 还是其他支持inline 的编译器都能编译通过。
inline_func()是个函数(inline的),既然是函数,那么就应该允许加入函数声明。我们对 foo.c 进行些小的修改,看看结果。
//foo.c inline int inline_func(int a); inline int inline_func(int a) { return a + 1; } int foo(void) { int x = 5; x = inline_func(x); return x; }
编译通过,但是这样的代码实际上是不符合c99标准的。c99标准中inline 关键字只能修饰函数定义,不能修饰函数声明。用gcc编译时如加入了 -std=c99 的选项(要求gcc严格遵守c99标准),就不能编译通过。报的错误如下:
In function `foo'
undefined reference to `inline_func
如果在声明时去掉inline,变成如下的代码:
int inline_func(int a); inline int inline_func(int a) { return a + 1; } int foo(void) { int x = 5; x = inline_func(x); return x; }
则完全没有问题,无论开启与否c99,都能编译通过。
更多的时候,我们一个inline函数要在多处使用,这时如果像普通函数那样在其他文件中也声明一下,比如下面在main.c 中添加了函数声明和调用。
int inline_func(int a); int foo(void); int main() { int a = foo(); a = inline_func(a); printf("a = %d", a); return 0; }
这样编译也能通过,但是通过查看汇编代码就会发现。只有foo()函数中对inline_func() 的调用被内联了,main()中还是传统的函数调用方式。说明这样用并没有达到我们期望的效果。正确的方式应该是将inline 函数放到头文件中定义。这样每个用到它的地方才会真正的内联。
#include <stdio.h> #include "inline_func.h" int foo(void); int main() { int a = foo(); a = inline_func(a); printf("a = %d", a); return 0; } foo.c #include "inline_func.h" int foo(void) { int x = 5; x = inline_func(x); return x; } inline_func.h #ifndef INLINE_FUNC_H_INCLUDED #define INLINE_FUNC_H_INCLUDED inline int inline_func(int a) { return a + 1; } #endif // INLINE_FUNC_H_INCLUDED
这个代码在最后链接时会报错说多次定义了inline_func()。查看汇编代码就会发现,在编译main.c 和 foo.c 时都生成了 inline_func 的代码,虽然main() 和 foo 都内联了inline_func(),所以inline_func()实际上是没用到的。但是有两份 inline_func()的代码还是会造成链接是的冲突。所以上面的代码还需要修改。一种简单的办法是将inline_func() 改为static 函数,也就是让它的作用域只在编译单元内。
inline_func.h #ifndef INLINE_FUNC_H_INCLUDED #define INLINE_FUNC_H_INCLUDED static inline int inline_func(int a) { return a + 1; } #endif // INLINE_FUNC_H_INCLUDED
这样修改之后就完全没问题了。其实到这里就可以了,不过有些人就喜欢在头文件中添加函数的声明,即使是inline函数也不例外。
inline_func.h #ifndef INLINE_FUNC_H_INCLUDED #define INLINE_FUNC_H_INCLUDED int inline_func(int a); static inline int inline_func(int a) { return a + 1; } #endif // INLINE_FUNC_H_INCLUDED
这样再编译又报错了。
error: static declaration of 'inline_func' follows non-static declaration
继续修改,改成这个样子就没问题了。
inline_func.h #ifndef INLINE_FUNC_H_INCLUDED #define INLINE_FUNC_H_INCLUDED static int inline_func(int a); static inline int inline_func(int a) { return a + 1; } #endif // INLINE_FUNC_H_INCLUDED
OK,就说这么多。inline 函数知道这么多基本就够用了。