inline 函数说明符

< c‎ | language

声明内联函数

语法

inline 函数声明 (C99 起)

解释

inline 说明符的目的是提示编译器做优化,譬如函数内联,这通常要求编译方能见到函数的定义。编译器能(并且经常)就优化的目的忽略 inline 说明符的存在与否。

若编译器进行函数内联,则它会以函数体取代所有对它的调用,以避免函数调用的开销(将数据置于栈上和取得结果),这可能会生成更大的可执行文件,因为函数可能会被重复多次。结果同仿函数宏,只是用于该函数的标识符和宏指代可见于定义点的定义,而不指代调用点的定义。

不管是否进行内联,内联函数都保证下列语义:

任何拥有内部链接的函数都可以声明成 static inline ,没有其他限制。

一个非 static 的内联函数不能定义一个非 const 的函数局部 static 对象,并且不能使用文件作用域的 static 对象。

static int x;
inline void f(void)
{
    static int n = 1; // 错误:非 const 的 static 对象在非 static 的 inline 函数中
    int k = x; // 错误:非 static 的 inline 函数访问 static 变量
}

若非 static 函数声明为 inline ,则必须在同一翻译单元中定义它。不使用 extern 的内联定义不会对外部可见,而且不会阻止其他翻译单元定义同一函数。这使得 inline 关键词成了 static 外另一种在头文件定义函数的方式,可以由同一程序的多个翻译单元包含该头文件。

若函数在一些翻译单元中声明为 inline ,它就不需要在处处皆声明为 inline :至多一个单元会提供常规的非 inline 非 static 函数,或是声明为 extern inline 的函数。称此翻译单元提供外部定义。为避免未定义行为,若在表达式中使用拥有外部链接的函数名,则程序中必须存在一个外部定义,见一个定义规则

内联函数的地址始终是外部定义的地址,但当以此地址进行函数调用时,调用内联定义(若存在于翻译单元中)还是外部定义是未指定的。定义于内联定义中的 static 对象与定义于外部定义中的 static 对象有别:

inline const char *saddr(void) // 用于此文件内的内联定义
{
    static const char name[] = "saddr";
    return name;
}
int compare_name(void)
{
    return saddr() == saddr(); // 未指定行为,调用可能是外部的
}
extern const char *saddr(void); // 外部定义也会生成

C 程序不应依赖于调用函数的内联版本还是外部版本,否则行为未指定。

关键词

inline

注解

inline 关键词是从 C++ 吸收的,但在 C++ 中,若函数声明为内联,则它必须在每一个翻译单元声明为内联,而且每一个内联函数都必须有准确相同的定义( C 中,定义可以相异,而依赖这些差异仅导致未指定行为)。另一方面, C++ 允许非 const 的函数局域 static 对象,而且所有来自一个内联函数不同定义版本的函数局部 static 对象都相同,但它们在 C 中不同。

示例

// file test.h
#ifndef TEST_H_INCLUDED
#define TEST_H_INCLUDED
inline int sum (int a, int b)
{
    return a+b;
}
#endif
 
// 文件 sum.c
#include "test.h"
extern inline int sum (int a, int b); // 提供外部定义
 
// 文件 test1.c
#include <stdio.h>
#include "test.h"
extern int f(void);
 
int main(void)
{
    printf("%d\n", sum(1, 2) + f());
}
 
// 文件 test2.c
#include "test.h"
 
int f(void)
{
    return sum(2, 3);
}

输出:

8

引用

  • C11 standard (ISO/IEC 9899:2011):
  • 6.7.4 Function specifiers (p: 125-127)
  • C99 standard (ISO/IEC 9899:1999):
  • 6.7.4 Function specifiers (p: 112-113)

参阅