1234567891011121314
// file.ccinline void foo(void){ /*函数体*/}// file.hvoid foo(void);// main.ccint main(){ foo();}
上面的编码会出现什么问题? 链接错误,显示foo未定义(undefined reference to `foo()’).
使用inline函数,意图是在函数调用处直接替换成函数体,省去函数调用,提高函数的执行效率.但编译器在处理的时候,真正的处理流程是什么样的呢?
我们知道,c/c++程序编译分为几个阶段,预处理->编译+汇编->链接. inline的处理阶段发生在编译阶段. 也就是说,在编译阶段完成后,目标模块的inline函数要么被替换了,要么没有被替换,但是链接时可以找到inline函数的定义.也就是说,在编译阶段之前,目标模块需要看到inline函数的实现.
拿引子程序来说,编译main.o目标模块时,编译器”看到”了foo的声明,此时它并不知道foo是要inline的.编译file.o目标模块时,编译器看到foo的实现,并且声明为inline,由于foo在file.o没有被使用到,所以,inline函数不被保留.链接的时候,当然也就找不到foo的定义实体了.针对此例子,我们可以在file.c定义一处函数,使用了一次foo(),编译就可以通过.
12345
//file.ccint foo2(){ foo();}
正确的做法是,inline函数的实现(定义)要跟随其函数声明放在.h文件中.编译器在编译阶段就可以看见函数实现,从而进行替换.(这一点有点向函数模板,函数模板也是要放在声明文件中,不能单独放在源文件中)
关键字inline必须与函数定义放在一起才能使函数真正内联,仅把inlilne放在函数声明的前面不起任何作用.
12345678910111213
//Foo不能内联inline void Foo(int x, int y);void Foo(int x, int y){ ...}//Foo内联void Foo(int x, int y);inline Foo(int x, int y){ ...}
inline是一种”用于实现的关键字”,而不是一种”用于声明的关键字”.
当多个源文件包含同一个inline函数,但是编译器又无视inline请求,如此一来,在每个目标模块中都有该函数的实现实例,造成重定义错误。把inline函数同时声明为static函数(限制其作用域为源文件内部),可以解决问题。