在extern inline函数中调用static inline函数为何会引发问题?
在extern inline函数中调用static inline函数为何会引发问题?
咱们先把你给出的代码示例摆清楚,方便分析:
lib.h
// lib.h #pragma once static inline int static_inline(int x) { return x; } inline int extern_inline(int x) { return static_inline(x); }
lib.c
// lib.c #include "lib.h" extern inline int extern_inline(int x);
app.c
// app.c #include "lib.h"
当编译app.c时,GCC会抛出警告,这背后的原因得从C语言里inline和static inline的特性说起,咱们拆解开讲:
先搞懂两个关键字的本质
static inline函数:它的作用域被限定在单个编译单元(简单说就是你正在编译的.c文件,以及它包含的头文件内容)里,编译器会优先把它内联展开,不会在目标文件里生成独立的函数定义(除非你用编译选项强制生成)。而且每个包含这个头文件的编译单元,都会拥有完全独立的static_inline副本——哪怕代码一模一样,它们也是互不干扰的不同函数。extern inline函数:按照C99标准和GCC的实现逻辑,它的意思是「这个函数的正式定义可能在其他编译单元里,当前编译单元可以选择内联它,也可以调用外部的正式定义」。在你的代码里,lib.c里的extern inline声明会让GCC在lib.c里生成extern_inline的独立函数定义,供其他编译单元调用。
问题出在哪?
你在extern_inline里调用了static_inline,这就埋下了一个潜在的行为不一致风险:- 如果编译器在编译
app.c时选择内联展开extern_inline,那么它会调用app.c自己的static_inline副本,逻辑正常; - 如果编译器选择不内联,转而调用
lib.c里的extern_inline正式定义,那么这个外部定义调用的是lib.c自己的static_inline副本。
虽然现在两个
static_inline的代码完全一样,但如果未来你修改了lib.h里的static_inline实现,却忘记重新编译所有包含它的编译单元(比如只编译了app.c没编译lib.c),就会出现同一个extern_inline函数,在某些场景下用新逻辑,某些场景下用旧逻辑的诡异bug。GCC的警告就是在提醒你这个潜在的坑。另外还有一个细节:从链接层面看,
lib.c里的extern_inline调用自己的static_inline是没问题的,但这种「跨编译单元依赖私有函数」的设计本身就不符合代码的模块化原则,很容易引发维护问题。- 如果编译器在编译
备注:内容来源于stack exchange,提问作者Jackoo
相关产品推荐
相关产品推荐

