c拓展语法学习

pragma

  #pragma是 C 语言的一种预处理指令,类似于#include。用于告诉编译器进行某种操作。pragma 单词本身的释义为“编译指令”。

  最简单的一种 pragma 可以在编译时输出文本提示。

1
2
3
4
5
#pragma message(">>> Compiling ...")

int main(void) {
    return 0;
}

  编译上面的 C 文件结果输出如下。

1
2
3
4
5
❯ gcc pragma.c
pragma.c:1:9: warning: >>> Compiling ... [-W#pragma-messages]
    1 | #pragma message(">>> Compiling ...")
      |         ^
1 warning generated.

_Pragma

  由于宏定义之间不能嵌套,当某种 pragma 想要复用时,无法通过#define复用,此时可以通过_Pragma指令,如下所示。

1
2
3
4
5
6
7
8
9
#define MSG _Pragma("message(\">>> Compiling ...\")")

MSG

_Pragma("message(\">>> Compiling ...\")")

int main(void) {
    return 0;
}

  编译后输出如下提示信息。其中的 note 消息可以忽略,关注warning: >>> Compiling ... [-W#pragma-messages]段即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
❯ gcc pragma.c
pragma.c:3:1: warning: >>> Compiling ... [-W#pragma-messages]
    3 | MSG
      | ^
pragma.c:1:13: note: expanded from macro 'MSG'
    1 | #define MSG _Pragma("message(\">>> Compiling ...\")")
      |             ^
<scratch space>:4:2: note: expanded from here
    4 |  message(">>> Compiling ...")
      |  ^
pragma.c:5:1: warning: >>> Compiling ... [-W#pragma-messages]
    5 | _Pragma("message(\">>> Compiling ...\")")
      | ^
<scratch space>:6:2: note: expanded from here
    6 |  message(">>> Compiling ...")
      |  ^
2 warnings generated.

  根据上面的编译输出结果,我们可以知道,如下两种编译指令是近似等价的。但是_Pragma语法本身可以放在#define中复用。

1
2
#pragma message(">>> Compiling ...")
_Pragma("message(\">>> Compiling ...\")")

pragma 指令功能表

指令 功能
clang diagnostic push 保存当前的诊断设置(哪些警告开、哪些关)到内部栈
clang diagnostic ignored “-Wexcessive-regsave” 告知编译器对接下来遇到的 -Wexcessive-regsave 警告保持沉默
clang diagnostic pop 从栈中恢复诊断设置,这样后面的代码不受影响

-Wexcessive-regsave: 这是一个在某些架构上(尤其是 ARM64)编译器生成代码时可能触发的警告:函数太复杂,编译器需要把大量寄存器保存/恢复到栈上,影响性能。通常在非常大的内联函数或深层嵌套调用时出现。

attribute

  __attribute__GCC(GNU Compiler Collection) 提供的一种语言扩展,用于在 C/C++ 代码中指定函数、变量、类型的特殊属性(attributes),从而告诉编译器对这些实体进行特定的优化、检查或行为控制。 它也被 Clang 等兼容 GCC 的编译器支持。其基本语法如下

1
__attribute__((attribute-list))
  • 可放在声明末尾,或紧跟在标识符之后。
  • 多个属性用逗号分隔,例如 __attribute__((aligned(8), packed))

常见属性表

函数属性

属性 说明
noreturn 函数永不返回(如 exitabort),帮助消除 unreachable-code 警告
format(archetype, string-index, first-to-check) 声明类 printf/scanf 函数的格式串检查,例如 format(printf, 1, 2)
nonnull(arg-index, ...) 声明指针参数不可为 NULL
const 纯函数 - 只依赖参数值,不读全局内存,无副作用(比 pure 更强)
pure 函数无副作用,返回值仅依赖参数和全局内存(可被 CSE 优化,但调用次数不可消)
malloc 返回新分配的内存指针,且该指针不会与任何已有指针别名
warn_unused_result 调用者忽略返回值时发出警告
used 即使未引用也保留函数代码(防止被链接器丢弃)
unused 抑制"未使用函数"警告
weak 弱符号 - 可被同名强符号覆盖,用于提供默认实现
constructor main() 之前自动执行(可带优先级参数)
destructor main() 返回后或 exit() 时自动执行
noinline 禁止内联此函数
always_inline 强制内联(即使优化级别不支持)
flatten 将此函数内的每个调用都视为 always_inline
hot 标记为热点路径,优化分支预测和指令布局
cold 标记为冷路径,优化代码体积而非速度
no_sanitize("sanitizer-name") 对此函数禁用指定 sanitizer(如 address、thread)
interrupt / interrupt_handler 声明中断处理函数(自动保存/恢复寄存器,使用特殊返回指令)
sentinel 参数列表必须以 NULL 结尾(如 execl
alloc_size(pos) / alloc_size(pos1, pos2) 标明第几个参数控制分配大小,辅助优化和安全检查
returns_nonnull 函数保证返回非 NULL 指针
leaf 函数不会回调当前编译单元内的任何函数
nothrow 函数保证不抛出 C++ 异常
target("feature") 为特定 CPU 特性编译此函数(如 target("avx2")

类型属性

属性 说明
aligned(N) 指定类型或变量的对齐字节数(N 为 2 的幂)
packed 紧凑布局 - 移除成员间的填充字节
deprecated / deprecated("message") 标记为已弃用,使用时产生警告
unavailable 标记为不可用,使用时产生错误
visibility("type") 符号可见性:defaulthiddeninternalprotected
mode(TI/QI/HI/SI/DI) 指定整数类型的宽度(如 __attribute__((mode(DI)))
may_alias 声明此类型可能与其他类型别名,抑制严格别名优化
transparent_union 透明联合体 - 传参时各成员类型可隐含转换
designated_init 只能通过指定初始化器初始化(可用于 union)
objc_root_class 标记 Objective-C 根类

变量属性

属性 说明
section("name") 将变量放入指定段(如 .init_array.bss.my_section
used 即使未引用也保留变量
unused 抑制"未使用变量"警告
aligned(N) 指定对齐(同类型属性,直接作用于变量)
packed 去除结构体成员对齐填充(作用于变量声明时)
cleanup(function) 变量离开作用域时自动调用给定函数(类似 C++ RAII)
weak 弱符号 - 可被同名强符号覆盖
tls_model("model") 指定 TLS 模型:global-dynamiclocal-dynamicinitial-execlocal-exec
noinit 变量不初始化为零(用于保持复位后的数据)

用法示例

1
2
3
4
5
6
7
8
9
typedef struct {
        acpi_sdt_header_t header;
        uint32_t          PointerToOtherSDT;
} __attribute__((packed)) rsdt_t;

__attribute__((noinline)) void compiler_barrier(void)
{ __asm__ volatile("" ::: "memory"); }

volatile float __x __attribute__((unused));

aligned(N) 做了两件事:

效果 说明
起始地址 变量/结构体地址满足 addr % N == 0
sizeof 补整 末尾补 padding 使 sizeof % N == 0

volatile 关键字

  volatile 是 C 语言的一个类型修饰符,用于告诉编译器:该变量的值可能在程序控制流之外被意外修改,因此编译器不能对该变量的访问进行某些优化(如缓存到寄存器、消除冗余读取等)。

  __asm__volatile可以一起使用,如下。

1
__asm__ volatile("inw %1, %0" : "=a"(ret) : "dN"(port));

编译器必须:

  • 保留这段汇编,即使输出没用
  • 每次都生成,不能合并
  • 保持原位,不和其它 volatile asm 重排
CC BY-NC-ND 4.0
最后更新于 Jul 14, 2026 15:52 UTC