• volatile 与 restrict


    12.5.2 volatile类型限定符


    volatile 限定符告知计算机,代理(⽽不是变量所在的程序)可以
    改变该变量的值。通常,它被⽤于硬件地址以及在其他程序或同时运
    ⾏的线程中共享数据。例如,⼀个地址上可能储存着当前的时钟时
    间,⽆论程序做什么,地址上的值都随时间的变化⽽改变。或者⼀个
    地址⽤于接受另⼀台计算机传⼊的信息。
    volatile的语法和const⼀样:
    olatile int loc1;/* loc1 是⼀个易变的位置 */
    volatile int * ploc; /* ploc 是⼀个指向易变的位置的指针 */
    以上代码把loc1声明为volatile变量,把ploc声明为指向volatile变量
    的指针。
    读者可能认为volatile是个可有可⽆的概念,为何ANSI 委员把
    volatile关键字放⼊标准?原因是它涉及编译器的优化。例如,假设有
    下⾯的代码:
    vall =x;
    /* ⼀些不使⽤ x 的代码*/
    val2 = x
    智能的(进⾏优化的)编译器会注意到以上代码使⽤了两次 x,但
    并未改变它的值。于是编译器把 x的值临时储存在寄存器中,然后在
    val2需要使⽤x时,才从寄存器中(⽽不是从原始内存位置上)读取x的
    值,以节约时间。这个过程被称为⾼速缓存(caching)。通常,⾼速
    缓存是个不错的优化⽅案,但是如果⼀些其他代理在以上两条语句之
    间改变了x的值,就不能这样优化了。如果没有volatile关键字,编译器
    就不知道这种事情是否会发⽣。因此,为安全起⻅,编译器不会进⾏
    ⾼速缓存。这是在 ANSI 之前的情况。现在,如果声明中没有volatile
    关键字,编译器会假定变量的值在使⽤过程中不变,然后再尝试优化
    代码。
    可以同时⽤const和volatile限定⼀个值。例如,通常⽤const把硬件
    时钟设置为程序不能更改的变量,但是可以通过代理改变,这时⽤
    volatile。只能在声明中同时使⽤这两个限定符,它们的顺序不重要,
    如下所⽰:
    volatile const int loc;
    const volatile int * ploc;
    12.5.3 restrict类型限定符
    restrict 关键字允许编译器优化某部分代码以更好地⽀持计算。它
    只能⽤于指针,表明该指针是访问数据对象的唯⼀且初始的⽅式。要
    弄明⽩为什么这样做有⽤,先看⼏个例⼦。考虑下⾯的代码:
    int ar[10];
    int * restrict restar = (int *) malloc(10 * sizeof(int));
    int * par = ar;
    这⾥,指针restar是访问由malloc()所分配内存的唯⼀且初始的⽅
    式。因此,可以⽤restrict关键字限定它。⽽指针par既不是访问ar数组
    中数据的初始⽅式,也不是唯⼀⽅式。所以不⽤把它设置为restrict。
    现在考虑下⾯稍复杂的例⼦,其中n是int类型:
    for (n = 0; n < 10; n++)
    {
    par[n] += 5;
    restar[n] += 5;
    ar[n] *= 2;
    par[n] += 3;
    restar[n] += 3;
    }
    由于之前声明了 restar 是访问它所指向的数据块的唯⼀且初始的⽅
    式,编译器可以把涉及 restar的两条语句替换成下⾯这条语句,效果相
    同:
    restar[n] += 8; /* 可以进⾏替换 */
    但是,如果把与par相关的两条语句替换成下⾯的语句,将导致计
    算错误:
    par[n] += 8; / * 给出错误的结果 */
    这是因为for循环在par两次访问相同的数据之间,⽤ar改变了该数
    据的值。
    在本例中,如果未使⽤restrict关键字,编译器就必须假设最坏的
    情况(即,在两次使⽤指针之间,其他的标识符可能已经改变了数
    据)。如果⽤了restrict关键字,编译器就可以选择捷径优化计算。
    restrict 限定符还可⽤于函数形参中的指针。这意味着编译器可以
    假定在函数体内其他标识符不会修改该指针指向的数据,⽽且编译器
    可以尝试对其优化,使其不做别的⽤途。例如,C 库有两个函数⽤于
    把⼀个位置上的字节拷⻉到另⼀个位置。在C99中,这两个函数的原型
    是:
    void * memcpy(void * restrict s1, const void * restrict s2, size_t n);
    void * memmove(void * s1, const void * s2, size_t n);
    这两个函数都从位置s2把n字节拷⻉到位置s1。memcpy()函数要求
    两个位置不重叠,但是memove() 没有这样的要求。声明s1和s2为
    restrict说明这两个指针都是访问相应数据的唯⼀⽅式,所以它们不能
    访问相同块的数据。这满⾜了memcpy()⽆重叠的要求。memmove()函
    数允许重叠,它在拷⻉数据时不得不更⼩⼼,以防在使⽤数据之前就
    先覆盖了数据。
    restrict 关键字有两个读者。⼀个是编译器,该关键字告知编译器
    可以⾃由假定⼀些优化⽅案。另⼀个读者是⽤⼾,该关键字告知⽤⼾
    要使⽤满⾜restrict要求的参数。总⽽⾔之,编译器不会检查⽤⼾是否
    遵循这⼀限制,但是⽆视它后果⾃负。

  • 相关阅读:
    来自极客标签10款最新设计素材系列七
    支持触摸设备的响应式HTML5音频播放器 AudioPlayer.js
    最流行的JavaScript库,jQuery不再支持IE旧版本
    来自极客标签10款最新设计素材系列六
    来自极客标签10款最新设计素材系列四
    推荐10款来自极客标签的超棒前端特效[第四期]
    响应式的无限滚动全屏dribbble作品集布局展示效果
    推荐10款来自极客标签的超棒前端特效[第五期]
    基于属性编程
    郁闷的企业软件开发
  • 原文地址:https://www.cnblogs.com/focus-z/p/14674644.html
Copyright © 2020-2023  润新知