九 052010
用了很久的编译器,在编译新的源程序时,其中一个动态链接库.so文件,忽然报undefined symbol错。很是奇怪。于是,查之。
首先报错的symbol是C++ name mangling(为了防止重名,对程序中名称做特殊处理)之后的,C++filt转换之后,把符号名在源码中grep了一把,发现是个函数名。这个函数名定义如下:
inline fun_name() {
...
}
在另外一个文件中有对该函数的引用,于是有这个声明: extern inline fun_name().问题就出在这个extern inline上。
标记了inline的函数可以接着标记extern吗?
什么是inline,一个函数被标记为inline之后,编译器就会在该函数的被调用点,使用函数体替代调用点。参数采取重命名的方式来防止变量名冲突。这样避免了函数调用的开销,能提升性能,但同时会增加可执行程序的大小。
什么是extern, extern 告诉编译器,某个函数/变量的定义可能在其他的C++源码文件中,编译器在编译时,就直接生成一个函数调用点,只在链接时在其他文件中查找该函数/变量的定义。
两个能同时用于定义一个函数吗?能,但是不同的编译器处理方式不同,在MAC OS系统下,IBM XL C/C++编译器中,若该函数声明在头文件里,就直接视为extern声明。而在gnu 编译器中,则直接视为inline声明。 “extern inline“在C++的标准里没有定义,所以各个编译器如何实现都不同。最好不要这么用。
因为inline是为了性能,所以去掉inline关键字后,这个bug也就过了。
教训就是:写程序一定要有标准,编译器不好做。是是非非不好衡量。还得有标准才行。
参考:
- http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=/com.ibm.vacpp6m.doc/language/ref/clrc07cplr243.htm
- http://www.greenend.org.uk/rjk/2003/03/inline.html
- http://stackoverflow.com/questions/216510/extern-inline

额,还有一种雷人的做法,C++里面头文件中类的类型定义部分用上inline,但是却不写上函数体,而是在源文件中加上。有的GCC能过,有的不行,但是过了都能正常跑,可能是编译器不严格吧。从语言的结构上来说,这个或许也是一种extern inline
我觉得要是真的做到编译器能标准处理这种extern inline问题,不会出现有的版本gcc能过,有的不能过,还是得靠理论上严格的形式验证。这个有难度。。。。
忘了从哪里看到,好像说函数的inline只能是在编译时,而不在链接时。
感觉inline修饰符的函数可以当作带类型的宏,若要在多个文件里面使用这个函数,比较保险的方法可以再在前面加个static,放到头文件里面。像这样:
xx.h //both included by a.c and b.c
static inline fun_name() {
…
}
inline是在编译时,不懂为什么要加static。你的意思是,只让 fun_name的作用域在a.c和b.c中?
囧,看别人代码都这样,具体就不敢说了…C的语义实在是微妙啊
刚刚google下,这篇讨论貌似很不错 http://topic.csdn.net/u/20071130/07/854b2db3-1f2b-40e6-9f03-95d0f7fac09b.html