大陆地区请使用VPN访问,欢迎提建议,关注LSKR Mastodon

详细解释C语言中的内联函数-C语言高级用法

本文详细解释了C语言重点内联函数的常规用法以及高级用法,同时示范了内联函数的很多错误用法。
详细解释C语言中的内联函数-C语言高级用法

内联函数的作用

在 C 语言中,inline 关键字用于建议编译器将函数 内联展开,也就是把函数的代码直接插入到调用处,从而 避免函数调用的开销。但是否真的内联,由编译器决定。

在 C 中,inline 函数通常具有两个目的:

请求编译器内联展开该函数(虽然不是强制,编译器可能忽略)。

错误示范

 myheader.h:
 inline void foo(); // 仅声明 这里是 仅声明 了一个 inline 函数 foo,但并没有提供定义(即函数体)。
 foo.c:
 inline void foo() {
     // ...
 }
 //这是对 foo 的定义(包含函数体),同样使用了 inline 关键字。

当前写法的问题:

如果你只在一个 .c 文件中定义 inline 函数(且未加 extern),编译器可能不会为它生成链接可见的符号,导致在其他文件中调用 foo() 时找不到定义。

  • myheader.h 中的 inline void foo(); 没有定义函数体;

  • foo.c 中定义了 inline 函数;

但这会导致其他源文件无法使用 foo(),因为 inline 函数不会自动生成链接符号,应将定义放到头文件中改用非 inline 的方式

static inline

为什么加了 static 就没问题?

 static inline void foo() {
     // ...
 }

加了 static 后,foo 的作用域就局限在当前 .c 文件里:

  • 每个 .c 文件有自己的一份 foo

  • 这些函数是“私有”的,不参与链接

  • 所以多个 .c 文件用同一个头文件不会冲突

分解解释:

inline 的作用是:

  • 建议编译器将函数体在调用处“展开”成内联代码,省去函数调用开销,更高效。

  • 适合:小函数、频繁调用的场景。

static 的作用是:

  • 把函数的作用域限制在当前 .c 文件。

  • 如果不加 static,你把一个函数定义写在头文件中,多个 .c 文件 #include 之后会导致 “多重定义”错误(link error)。

  • 加了 static 后,每个 .c 文件都有一份自己的副本,彼此互不干扰。

什么时候该用 static inline

  • 小工具函数(如 max(), swap(), list_add() 等)

  • 多个 .c 文件都需要用

  • 函数体很小,性能敏感

  • 不希望暴露成链接符号

不用!

  • 函数体太大(会膨胀代码体积)

  • 你希望别的文件能访问它(那就不要 static

问题分析:

 // myheader.h
 inline void foo(); // 仅声明
 
 // foo.c
 inline void foo() {
     // ...
 }

但这要求你:

  • 在某个 .c 文件里要有 唯一定义

  • 所有用的地方都只能用声明,不能定义

  • 不然仍然会多重定义

你这个例子中,如果使用的是 C 编译器(如 gcc foo.c),那会出现以下问题:

  • myheader.h 中,你 只声明了一个 inline 函数,但是没有提供定义。

  • 然后你在 foo.c 中定义了它。

inline 函数若想在其他文件中使用,必须在头文件中提供定义。因为编译器在编译其他源文件时,需要看到函数体,才能考虑内联或生成调用。

为啥要写在头文件中?

因为内联函数是编译器在编译阶段直接“插入”调用点的代码。每个用到它的编译单元(.c 文件)都需要看到这个函数的定义,而不仅仅是声明。

如果你只写了声明:

 inline void foo();  // 👈 只有这个,别的文件编译不了 foo

那其它文件编译器就不知道 foo() 的具体内容,无法展开成内联代码,也无法链接(除非你链接了一个带外部定义的 foo,但那就和 inline 本意矛盾了)。

内联函数不在头文件中的用法

那只写 inline 就不能用吗?

可以 —— 但你要写成“外部内联声明+单一定义”的格式(太复杂,不推荐初学者这么做):

 // myheader.h
 extern void foo(); // 普通声明,不要用 inline
 
 // foo.c
 inline void foo() {
     // ...
 }
 extern void foo(); // 告诉编译器你会用到这个函数,强制生成符号

但这个方式较为复杂,不推荐,除非你特别清楚目的。

所以实际开发中,为了方便和安全,大家基本都用 static inline 放头文件

写法是否安全放在头文件会不会冲突推荐程度
inline void foo()❌ 不安全(可能多重定义)⚠️ 高❌ 不推荐
static inline void foo()✅ 安全,每个 .c 一份✅ 不会✅ 强烈推荐
extern inline + 单一定义✅ 安全但麻烦✅ 不会🔧 高级用法

总结

内联函数用于小函数,提高性能,通常用法有两种,

一:常见用法,直接写成static inline在头文件中,

二:写成外部内联声明+单一定义,这是放在源文件中的用法,其他用法由于语法等问题,不成立。(麻烦所以不建议使用),所以内联有且只有一种用法 static inline

补充C++语言内联机制大不同

inline 的函数,即使在多个 .cpp 文件中包含,也不会重复定义,因为 inline 函数具有“多重定义容忍性”。(C++属性,在C中没有这个机制)

 // math_utils.h
 inline int square(int x) {
 return x * x;
 }

这样的定义用法在C语言是不推荐的。这是在C++会出现的用法,原因就是C++具有“多重定义容忍”性特性。

NextGen Digital... Welcome to WhatsApp chat
Howdy! How can we help you today?
Type here...