C中的内联函数行为

来源:互联网 发布:宽带动态薪酬模型知乎 编辑:程序博客网 时间:2024/04/29 08:27

转自:http://blog.csdn.net/overcomeunicom990702/article/details/2412850 

 

C标准规定内联只是对C编译器的一个建议而不是强制要求,编译器可以选择内联也可以选择不内联。
cc不会内联函数,除非-xO3及以上,并且只有后端认为内联能够带来性能上的提升时才会进行内联,
没有办法强制cc对函数进行内联。
C99对inline function的有关描述可见6.7.4

对于static inline函数,cc根据编译选项及后端判断,如果不能内联,则产生一个reference,到时候调
用该函数,由于是static的,那么其可见范围仅在本TU有效,不会造成多重定义。

 对于外部链接属性的函数,如果有inline关键字修饰,则必须要有定义(对cc有效)。
对于extern inline函数则要复杂一些,有两种形式:

1.inline definition
2.external defineition

C标准还规定,具有内部链接属性的函数可以成为内联函数,如果函数具有外部链接属性,则必须遵
守如下限制:1,如果函数声明为inline,则必须被定义在相同的TU中,
即extern inline void foo(){...}应该是在TU中而不是头文件出现。如果同一TU中所有对一个函数
的声明包含inline但没有extern,则在该TU中该函数将是inline definition。对函数的调用是调用
inline definition还是external definition,这是未指定的。

任何引用到函数,如果这个函数不能被内联,那么这个函数必须是一个外部或全局的符号,由其它
object文件或库在链接时提供。

具有外部链接属性的inline函数不能包含具有static storage duration的可修改的对象的定义,也
不能包含具有内部链接属性的标识符(gcc/cc都不care这一条,bar1函数定义了静态可变对象,但仍可通过
以下摘自标准,我没理解错吧:)
quote:
An inline definition of a function with external linkage shall not contain a definition of a
modifiable object with static storage duration, and shall not contain a reference to an
identifier with internal linkage.
end quote)。
下面给出不同编译器对内联的处理情况:
1.使用cc的情况下(Sun C 5.9 SunOS_i386 Build47_dlight 2007/05/22)

//-----------------------t1.c#include <stdio.h>static inline void foo() // <---------------- static inline function,通过nm看到其是local的...{    printf("foo in %s, %d", __FILE__, __LINE__);}extern void bar1();inline void bar1()  // <---------------------- extern inline function,通过nm看到其是global的...{    static int value = 0;    ++value;    foo();}//-----------------------t2.c#include <stdio.h>inline void foo()  // <---------------------- inline definition function,通过nm看不到它的踪影(1)...{    printf("foo in %s, %d", __FILE__, __LINE__);}extern inline void bar2() // <---------------- extern inline function,通过nm看到其是global的...{    foo();  // <---------------------- 由于同TU的foo是inline definition function,找不到,编译器报错}//------------------------t.c#include <stdio.h>extern void bar1();       // <------------- 正确声明联函数extern inline void bar2();// <------------- 引发编译器错误,如果有inline,则要见到定义(2)int main()...{    bar1();    bar2();    return 0;}//其中1和2都需要修改才能正确通过编译



 

2.使用gcc的情况下(gcc 版本 4.1.1 20070105 (Red Hat 4.1.1-52))
//-----------------------t1.c#include <stdio.h>static inline void foo() // <---------------- static inline function,通过nm看到其是local的...{    printf("foo in %s, %d", __FILE__, __LINE__);}extern void bar1();inline void bar1()  // <---------------------- extern inline function,通过nm看到其是global的...{    static int value = 0;    ++value;    foo();}//-----------------------t2.c#include <stdio.h>inline void foo()  // <---------------------- inline definition function,通过nm看到其是global的...{    printf("foo in %s, %d", __FILE__, __LINE__);}extern inline void bar2() // <---------------- extern inline function,通过nm看不到它的踪影...{    foo(); }//------------------------t.c#include <stdio.h>extern void bar1();       // <------------- 正确声明内联函数extern inline void bar2();// <------------- 正确声明内联函数int main()...{    bar1();    bar2();    return 0;}


 


结论:不管是gcc/cc都不完全遵守C99标准,gcc/cc在处理内联函数上存在不同,根据实际应用,我们可以把内联函数分成两种:
1.只为本TU使用:只能被本TU使用的,我们使用static inline,这样使得其具有内部链接属性
2.为其它TU使用:要求能被其它TU使用,这时候在整个程序中只能有一份定义,因此这个定义必须放在某TU中,为保证可移植,
统一使用extern return_type function_name(parameter_list); inline return_type function_name(parameter_list);的
方式进行定义,在其它TU要使用到时使用extern return_type function_name(parameter_list);的方式进行声明。
实际的使用还得根据当前使用的cc/gcc的版本的实际处理方法来进行相应调整。
对于老的cc,当同一TU中定义有inline definition function时,就会导致static inline 函数不能调用static inline函数/extern inline 函数,因此应该避免inline definition function的出现,而且,extern return_type function_name(parameter_list); inline return_type function_name(parameter_list);会被认为是inline definition function,在特定的平台需要特别处理