
C语言提供了一些关键字用于对变量的存储方式进行控制主要包含register、volatile等。对于函数中的局部变量如果没有强制指定要求可能直接优化成寄存器访问不一定在栈中具体取决于变量的长度大小和编译器的优化策略。对于局部变量优化成寄存器访问速度会比栈中的变量快很多。这是因为栈中的变量需要通过内存访问涉及到Cache机制、内存寻址等而内核中的寄存器可以直接存取访问速度要快很多。不过优化后并非没有弊端在调试时优化成寄存器访问的局部变量很多无法直接通过调试窗口查看。对于变量的地址这就涉及到对变量的存储的更精细的控制包括register和volatile关键字。register关键字可以要求编译器将局部变量分配到寄存器中从而提高访问速度但是不能保证变量一定分配到寄存器中内部寄存器的数量是有限的(如Cortex-M结构内部数值寄存器对应的就是r0-r12)对于比较大的结构体变量、数组等编译器仍然会选择栈中的存储方式。volatile关键字则正好相反要求编译器必须访问实际的内存地址不能优化成内部寄存器访问(这里的内部寄存器指的是Cortex-M结构中的r0-r12数据寄存器而并非功能性寄存器如UART配置寄存器。关于volatile关键字可以用于如下场景。并行设备的硬件寄存器如模块功能寄存器。一个中断服务子程序中会访问到的非自动变量Non-automatic variables)。多线程应用中被几个任务共享的变量volatile仅保证每次访问变量的最新值阻止对地址访问的优化并不能保证其原子性在多线程环境下也不能代替锁机制。可以使用C11的_Atomic关键字来实现原子操作。精通volatile的运用在嵌入式底层中十分重要也是嵌入式C从业者的基本要求之一。关于volatile、register、__Atomic关键字具体示例如下所示。#include int main(int argc, char *argv[]) { int a1 1; // 局部变量由编译器决定存储方式 register int a2 2; // 局部变量要求编译器将变量分配到寄存器中(对于小的变量一般会优化成寄存器访问) volatile int a3 3; // 局部变量要求每次访问都从内存中读取 _Atomic int a4 4; // 局部变量支持原子操作(底层一般依赖volatile实现) a1 1; a2 1; a3 1; a4 1; printf(a1: %d\n, a1); printf(a2: %d\n, a2); printf(a3: %d\n, a3); printf(a4: %d\n, a4); return 0; }具体的输出结果如下所示。运行结果表明对于局部变量编译器一般会优化成寄存器访问对于volatile关键字每次访问都从内存中读取。