主要观点:Linux 内核用 C 编写并利用 GCC 提供的扩展,2022 年从 GCC/Clang -std=gnu89
迁移到 -std=gnu11
,文章探讨内核中这些 GNU 扩展的使用笔记。
关键信息和重要细节:
- Statement expressions:常用于宏中,如在
_wait_event
宏中用于循环控制等。 - Local labels:某些宏利用此扩展在替换列表中重启 for 循环,如
_wait_event
宏中的__label__ __out
。 - Labels as values and computed goto statements:字节码解释器常用,BPF 等使用,在不同代码位置(如
drm_exec_retry_on_contention
)有应用,在 PDC 和 PIC 中各有特点。 typeof
和__auto_type
:typeof
在众多代码中使用,__auto_type
有少量出现,C23 标准化了它们。- Conditionals with omitted operands:“Elvis 算子”
x?: y
在众多代码中使用。 - Empty structures:C 标准规定成员列表为空时行为未定义,空结构扩展可在配置选项禁用功能时使用,如
syscall_user_dispatch
结构的定义。 - Case ranges:在内核中常用,可在 switch 语句中指定连续值范围的单个 case 标签。
- Object size checking:glibc 2004 引入
_FORTIFY_SOURCE
,Linux 内核 2017 - 07 引入CONFIG_FORTIFY_SOURCE
,两者利用内联函数和__builtin_object_size
进行实现,Clang 也有相关实现。 - Pragmas:
#pragma GCC diagnostic
用于禁用本地诊断,#pragma GCC visibility("hidden")
用于强制外部符号的直接访问,#pragma GCC poison
用于禁止某些不期望的标识符,结构布局 pragmas 常用。 - Inline assembly:用于硬件交互、性能优化、特殊设施实现等。
Built-in functions:
- 特殊机器码指令:GCC 提供内置函数生成特定任务的机器码指令。
__builtin_choose_expr
:类似? :
,条件为常量表达式,返回类型不受提升规则影响,在 GCC 中 C++不支持。__builtin_constant_p
:识别表达式是否可求值为常量,可用于条件静态断言、替代代码路径、常量折叠优化等,但常被滥用导致内核不能用-O0
编译。__builtin_expect
:用于likely
和unlikely
宏给编译器优化提示。__builtin_frame_address
:用于栈跟踪实用程序。__builtin_offsetof
:用于实现offsetof
。__builtin_*_overflow
:用于溢出检查。__builtin_prefetch
:作为prefetch
和prefetchw
的默认实现。__builtin_unreachable
:用于告知不可达性以进行优化或抑制诊断。__builtin_types_compatible_p
:常用于模拟 C11static_assert
,或实现 C++函数重载等。
- Function attributes:
tools/include/linux/compiler.h
定义许多常用属性的宏,tools/testing/selftests
有一些__attribute__((constructor))
用于初始化,__attribute__((error(...)))
用于静态断言等。 - Variable attributes:
__attribute__((cleanup(...)))
在变量超出范围时运行函数,include/linux/cleanup.h
基于此定义DEFINE_FREE
和__free
。 - Type attributes:
__attribute__((aligned(...)))
和__attribute__((packed))
常用于控制结构布局。 Language dialects:
-fno-delete-null-pointer-checks
:假设程序可安全地解引用空指针,代码或数据元素可位于地址零。-fno-strict-aliasing
:C11 标准定义的严格别名规则,编译器可利用其进行优化,可通过-fno-strict-aliasing
禁用,Linus Torvalds 对其有保留意见。-fno-strict-overflow
:在 GCC 中等同于-fwrapv -fwrapv-pointer
,使有符号整数溢出使用环绕语义定义,虽避免未定义行为但可能隐藏意外算术溢出错误。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。