鱼C论坛

 找回密码
 立即注册
查看: 22|回复: 2

关键字

[复制链接]
发表于 3 小时前 From FishC Mobile | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
inline,restrict,volatile,const,_Atomic这些关键字的含义和用法
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 3 小时前 | 显示全部楼层
C语言关键字含义与用法详解


1. inline
含义:向编译器建议,将该函数在调用处展开(内联),以避免函数调用的开销(如栈帧创建/销毁)。
用法与注意
*   仅是一个“建议”,编译器有权忽略。对于短小、频繁调用的函数效果显著。
*   C99中,inline函数定义必须放在头文件中,除非该函数是static的。
*   用于头文件时,通常与 static 结合(C99之前的惯用法),或使用 extern(C99标准做法)。


  1. // 在头文件 utils.h 中
  2. // C99标准方式:在头文件中用 extern inline 声明,在一个.c文件中提供定义
  3. // 更常见的简单用法(C99前,或static函数):
  4. static inline int max(int a, int b) {
  5.     return (a > b) ? a : b;
  6. }
  7. // 编译器可能会将 `result = max(x, y);` 直接替换为 `result = (x > y) ? x : y;`
复制代码


2. restrict
含义:一个[C99引入的]指针限定符。它向编译器承诺:在该指针的生命周期内,只有它(或直接/间接从其派生的指针)用于访问其所指向的对象。这为编译器进行激进优化(如指令重排、省略重复读取)提供了依据。
用法与注意
*   仅用于指针
*   是程序员给编译器的承诺。如果违反此承诺(即存在别名访问),结果将是未定义的(可能引发错误)。
*   C++中无此关键字,但主流编译器(如GCC, Clang)提供 __restrict 扩展。
*   常用于函数参数中的指针,尤其是内存操作函数。


  1. // 经典例子:memcpy 和 memmove 的假设
  2. // memcpy 的源和目的内存绝不能重叠,其原型使用restrict
  3. void *my_memcpy(void *restrict dest, const void *restrict src, size_t n);
  4. // 编译器可以假设 dest 和 src 指向的区域不重叠,从而可能使用更快的复制方式

  5. int a[10];
  6. // 假设 func 用 restrict 指针参数接收 a
  7. func_with_restrict_ptr(a); // 在func执行期间,不应通过 a[i] 等其他方式访问该数组
复制代码


3. volatile
含义:告诉编译器,该变量的值可能被程序之外的代理(如硬件、中断服务例程、另一个线程等)意外改变。因此,编译器必须每次都从内存中重新读取它的值,并且对它的写操作必须立即写回内存。
用法与注意
*   防止编译器做“过度优化”,如删除“看似无用”的读/写操作。
*   常见场景
    *   内存映射的硬件寄存器。
    *   中断服务程序修改的全局变量。
    *   多线程/任务共享的全局变量(但请注意,volatile不保证原子性,也不能替代内存屏障或原子操作/锁)。


  1. // 硬件寄存器示例
  2. volatile uint32_t *const status_reg = (uint32_t *)0x40021000;
  3. while ((*status_reg & 0x01) == 0) { // 每次循环都会从地址0x40021000读取,不会被优化成只读一次
  4.     // 等待状态位被硬件置1
  5. }

  6. // 中断服务程序(ISR)示例
  7. volatile int interrupt_occurred = 0;
  8. void ISR(void) {
  9.     interrupt_occurred = 1; // ISR中修改
  10. }
  11. int main(void) {
  12.     while (!interrupt_occurred) { // 编译器不会将此优化为 if (!interrupt_occurred) while(1);
  13.         // 正常任务
  14.     }
  15.     // 处理中断
  16. }
复制代码


4. const
含义:声明一个对象为“只读”。尝试修改一个用const定义的对象,会导致编译错误。
用法与注意
*   保护数据:防止代码意外修改,提高代码可读性和安全性。
*   指针与const:位置是关键。
    *   const int *p; (或 int const *p;):指向常量的指针,指针本身可改,指向的内容不可通过p改。
    *   int * const p;:常量指针,指针本身不可改,指向的内容可通过p改。
    *   const int * const p;:指向常量的常量指针,两者都不可改。
*   函数参数:用const修饰指针或引用参数,表明函数内部不会修改该数据。
*   C++中用途更广(如const成员函数)。


  1. // 保护变量
  2. const double PI = 3.14159;
  3. // PI = 3.14; // 错误!

  4. // 指针的不同const用法
  5. int a = 10, b = 20;
  6. const int *p1 = &a; // 指向常量的指针
  7. // *p1 = 30; // 错误!不能通过p1修改a的值
  8. p1 = &b;     // 正确,p1本身可以指向别的地址

  9. int * const p2 = &a; // 常量指针
  10. *p2 = 30;    // 正确,可以通过p2修改a的值
  11. // p2 = &b;  // 错误!p2本身不能指向其他地址

  12. // 函数参数保护
  13. void print_string(const char *str) { // 承诺不会修改str指向的字符串
  14.     printf("%s", str);
  15.     // str[0] = 'A'; // 这行如果取消注释,会导致编译错误
  16. }
复制代码


5. _Atomic (C11)
含义:C11标准引入的[原子类型限定符]。原子操作是指一个不可分割的操作。在多线程环境中,对一个_Atomic变量的读写操作是线程安全的,不会出现数据竞争(Data Race)。
用法与注意
*   用于声明一个原子类型的变量。
*   需要包含 <stdatomic.h> 头文件(使用 atomic_int 等类型名时,可省略 _Atomic 关键字,更推荐)。
*   对原子变量的操作应使用专门的原子操作函数(如 atomic_loadatomic_storeatomic_fetch_add)或重载的操作符(C++风格,C语言本身不支持),以确保正确的内存序语义。
*   这是实现线程安全的基础工具之一,但复杂的同步仍需结合互斥锁等机制


  1. #include <stdatomic.h>
  2. #include <threads.h>

  3. // 声明一个原子计数器
  4. _Atomic int counter = ATOMIC_VAR_INIT(0); // 或 atomic_int counter = 0;

  5. int thread_func(void* arg) {
  6.     for (int i = 0; i < 10000; ++i) {
  7.         atomic_fetch_add(&counter, 1); // 原子加1操作
  8.         // 等价于(宽松内存序下): counter++;
  9.     }
  10.     return 0;
  11. }

  12. // 在主函数中创建多个线程运行 thread_func
  13. // 最终 counter 的值将是 线程数 * 10000,不会出现因竞争导致的数据丢失。
复制代码

总结速查表
*   inline:函数内联建议,优化小型频繁调用函数。
*   restrict (C):指针独占访问承诺,为编译器优化开绿灯。
*   volatile:变量易变警告,阻止编译器做相关优化,用于硬件/中断/共享变量(非线程安全保证)。
*   const:只读声明,保护数据,提高代码健壮性。
*   _Atomic (C11):原子类型声明,实现无数据竞争的读写,是多线程编程的基础。


以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 半小时前 | 显示全部楼层
inline 省跳转,restrict 省猜测,
volatile 防缓存,const 防手贱,
Atomic 防并发翻车。

inline
建议编译器把函数代码直接展开,少一次函数跳转。

restrict
告诉编译器:这个指针独占内存,不会和别的指针指同一块。

volatile
告诉编译器:变量随时可能被外部修改,每次都必须重新读。

const
承诺不修改变量或指针指向的数据。

_Atomic
变量的读写是不可拆分的原子操作,防止并发数据竞争。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-12-17 17:53

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表