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 函数知道这么多基本就够用了。