gcc 编译器对 inline 函数的支持

时间:2022-11-29 02:05:58

C99版的C语言引入了inline关键字开始支持inline 函数,在这之前传统的C语言(C89)是没有inline 关键字的,也不支持inline 函数。不过大多数 C89 的编译器都将inline作为一种附加特性早早的就加进去了。gcc 也不例外,不过gcc增加inline特性时C99还没定型,gccinline 的语意与C99也有些许的区别。这里就主要说说gcc 中的inline 特性。

 

另外,本文只讨论C语言,C++标准中很早就支持inline,不过inline的语意CC++ 是有细微差别的。

先举一个最简单的例子

//main.c
#include <stdio.h>

int foo(void);
int main()
{
int a = foo();
printf("a = %d", a);
return 0;
}

//foo.c
inline int inline_func(int a)
{
return a + 1;
}
int foo(void)
{
int x = 5;
x = inline_func(x);
return x;
}

这个是inline 最简单的用法,无论是gcc 还是其他支持inline 的编译器都能编译通过。

 inline_func()是个函数(inline的),既然是函数,那么就应该允许加入函数声明。我们对 foo.c 进行些小的修改,看看结果。

//foo.c
inline int inline_func(int a);
inline int inline_func(int a)
{
return a + 1;
}
int foo(void)
{
int x = 5;
x = inline_func(x);
return x;
}

编译通过,但是这样的代码实际上是不符合c99标准的。c99标准中inline 关键字只能修饰函数定义,不能修饰函数声明。用gcc编译时如加入了 -std=c99 的选项(要求gcc严格遵守c99标准),就不能编译通过。报的错误如下:

In function `foo'

undefined reference to `inline_func

 

如果在声明时去掉inline,变成如下的代码:

int inline_func(int a);
inline int inline_func(int a)
{
return a + 1;
}
int foo(void)
{
int x = 5;
x = inline_func(x);
return x;
}

则完全没有问题,无论开启与否c99,都能编译通过。

更多的时候,我们一个inline函数要在多处使用,这时如果像普通函数那样在其他文件中也声明一下,比如下面在main.c 中添加了函数声明和调用。


int inline_func(int a);
int foo(void);
int main()
{
int a = foo();
a = inline_func(a);
printf("a = %d", a);
return 0;
}

这样编译也能通过,但是通过查看汇编代码就会发现。只有foo()函数中对inline_func() 的调用被内联了,main()中还是传统的函数调用方式。说明这样用并没有达到我们期望的效果。正确的方式应该是将inline 函数放到头文件中定义。这样每个用到它的地方才会真正的内联。


#include <stdio.h>
#include "inline_func.h"
int foo(void);
int main()
{
int a = foo();
a = inline_func(a);
printf("a = %d", a);
return 0;
}

foo.c
#include "inline_func.h"
int foo(void)
{
int x = 5;
x = inline_func(x);
return x;
}

inline_func.h
#ifndef INLINE_FUNC_H_INCLUDED
#define INLINE_FUNC_H_INCLUDED
inline int inline_func(int a)
{
return a + 1;
}

#endif // INLINE_FUNC_H_INCLUDED

这个代码在最后链接时会报错说多次定义了inline_func()。查看汇编代码就会发现,在编译main.c 和 foo.c 时都生成了 inline_func 的代码,虽然main() 和 foo 都内联了inline_func(),所以inline_func()实际上是没用到的。但是有两份 inline_func()的代码还是会造成链接是的冲突。所以上面的代码还需要修改。一种简单的办法是将inline_func() 改为static 函数,也就是让它的作用域只在编译单元内。

 inline_func.h
#ifndef INLINE_FUNC_H_INCLUDED
#define INLINE_FUNC_H_INCLUDED
static inline int inline_func(int a)
{
return a + 1;
}

#endif // INLINE_FUNC_H_INCLUDED

这样修改之后就完全没问题了。其实到这里就可以了,不过有些人就喜欢在头文件中添加函数的声明,即使是inline函数也不例外。

 inline_func.h
#ifndef INLINE_FUNC_H_INCLUDED
#define INLINE_FUNC_H_INCLUDED
int inline_func(int a);
static inline int inline_func(int a)
{
return a + 1;
}
#endif // INLINE_FUNC_H_INCLUDED

这样再编译又报错了。

error: static declaration of 'inline_func' follows non-static declaration

 

继续修改,改成这个样子就没问题了。

 inline_func.h
#ifndef INLINE_FUNC_H_INCLUDED
#define INLINE_FUNC_H_INCLUDED
static int inline_func(int a);
static inline int inline_func(int a)
{
return a + 1;
}
#endif // INLINE_FUNC_H_INCLUDED

OK,就说这么多。inline 函数知道这么多基本就够用了。