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,在特定的平台需要特别处理