c语言中的volatile到底做了什么?

最近发现身边很多同事对volatile理解有些偏差,我也本着求证的态度做了一番调查写下此文。

一些文章都会下这样定义volatile:“volatile修饰的变量会取消内存优化,使cpu每次都从内存中读写变量。”这样的说法大体上是成立的,但是严格的说volatile并不能越过cache机制直接访问DDR,原因是cache机制是对用户透明的,即使在kernel中要想操作cache也需要通过专用的api才能做到,具体api这里不做过多讨论。那么volatile到底做了什么呢?说明这个事情需要用到汇编。

我们先看一个非常简单的c代码,代码里分别读取了volatile指针和普通指针的值输出,我们看看编译器是怎么处理volatile修饰的。

int main(int argc, char const *argv[])
{
    int *buf1;
    volatile int *buf2;
    int i;

    buf2 = buf1 = (int*)malloc(4);
    for(i=0; i<10; ++i) {
        printf("0x%x 0x%x\n", *buf1, *buf2);    
    }   
    return 0;
}

使用O3优化编译,然后反汇编出指令。

arm-linux-gnueabi-gcc test.c -o test -O3
arm-linux-gnueabi-objdump -D test | less

得到汇编指令如下:

00010340 <main>:
   10340:       e92d41f0        push    {r4, r5, r6, r7, r8, lr}
   10344:       e3a00004        mov     r0, #4
   10348:       ebfffff0        bl      10310 <malloc@plt>
   1034c:       e3a0400a        mov     r4, #10
   10350:       e1a05000        mov     r5, r0
   //读取buf1的值到r7
   10354:       e5907000        ldr     r7, [r0]
   //读取printf的字符串到r6
   10358:       e59f601c        ldr     r6, [pc, #28]   ; 1037c <main+0x3c> 
//for循环开始 {
    //读取buf2到r2
   1035c:       e5952000        ldr     r2, [r5]
   //buf1传参给printf
   10360:       e1a01007        mov     r1, r7
   //字符串传参给printf
   10364:       e1a00006        mov     r0, r6
   //调用printf
   10368:       ebffffe5        bl      10304 <printf@plt>
   1036c:       e2544001        subs    r4, r4, #1
   10370:       1afffff9        bne     1035c <main+0x1c>
   // } for循环结束
   10374:       e1a00004        mov     r0, r4
   10378:       e8bd81f0        pop     {r4, r5, r6, r7, r8, pc}
   1037c:       00010518        andeq   r0, r1, r8, lsl r5

从这个例子我们看到编译器在处理volatile修饰的buf2时每次的都会用ldr读取指针,而普通指针buf1只会在进入循环前读取一次,volatile修饰的变量可以避免程序在运行过程中指针内容被修改的问题,但是ldr指令不可能越过cache机制所以严格的说并不是直接访问内存。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值