01 September 2015

在C/C++中,內联(inline)指的是在使用函数的地方不进行函数调用,而是将函数的实现代码插入到此处。 这样能够以增加代码大小为代价,省下函数调用过程产生的开销,加快程序执行速度。 內联属于编译器的一个优化措施,而inline关键字就是用来告诉编译器,希望对指定的函数做內联优化。

所谓“希望”,意思就是这仅仅是程序员对编译器的优化建议,并不能强制编译器必须将指定的函数內联。 因此,如果一定要将一个函数內联,用inline关键字是不行的,需要使用编译器扩展或配合编译器优化选项。

早期版本的C语言标准,例如C89,并没有inline关键字。C++语言先引入了这个关键字,后来的C语言标准,如C99,将其借鉴了进来。 在inline关键字进入C语言标准之前,很多C编译器,例如GCC,已经把它作为一项编译器扩展支持了。 但问题是,这些编译器扩展中inline关键字的意义与后来的C99标准并不一致。这就导致了代码兼容性的问题。

Clang是一个符合C99标准的编译器。在它的语言兼容性页面,专门针对inline关键字做了说明。 在C99中,被标为inline的函数定义只是用来內联使用的,并不提供该函数的一个外部定义。也就是说,如果在使用函数的地方编译器没有內联,那么程序就必须在别处提供一个该函数没inline标记的定义以供调用。 否则,链接时会报“找不到符号”的错误。例如,下面的C程序用Clang编译时就会报错:

inline int add(int i, int j) { return i + j; }

int main() {
  int i = add(4, 5);
  return i;
}

GCC(在5.0版本之前)默认采用GNU89模式,也就是C89标准加上它自己的一些扩展。inline关键字在GNU89并没有C99那样“只是用来內联使用”的含义,因此用GCC编译上述程序就没有问题。

要让上述程序被Clang编译通过,有以下几个方法:

  1. 给add函数添加static关键字(前提是这个函数只在当前文件使用,这样的话编译器就知道它不需要一个外部定义了);
  2. 去掉inline关键字;
  3. 另写一个没有inline关键字的add函数(为避免重复定义,另写的是函数声明);
  4. 给Clang加上–std=gnu89的选项。

维基百科上列出了使用inline关键字可能带来的一些问题,并指出它并没有那么值得用。 我自己没有使用过这个关键字,而且以后也不会用。是否內联优化一个函数还是交给编译器自己决定吧,程序员可以做些更有意义的事情。