volatilerestrict是C和C++中的两个关键字,都用于指示编译器优化。

volatile

volatile的本意是“易变的”,用法和const一样:

volatile int a; // 易变的int变量a
volatile int *p; // 指向易变位置的指针p

这个关键字的用处是什么?考虑下面的代码:

val1 = a;
/*
一段没有使用a值的代码
*/
val2 = a;

默认情况下,聪明的编译器可以注意到两段代码之间没有使用x。所以在第一次赋值时,会将a值放入寄存器,并在第二次赋值的时候直接从寄存器读取值,不用返回内存或cache,提高效率。

但是,如果你的程序是并发程序,或者在中间的代码里使用一些“意想不到的方式”改变了a的值(比如内联汇编),编译器却不知道,程序就会得出错误的结果。这时就需要给a加上volatile,语义即为“这个变量可能在中途在你看不到会被改变”,这样一来,编译器就不会做优化,得到正确结果。

volatile和const看上去是矛盾的,但是他们可以一起用。同样的道理,const只是表示“我这里不能赋值更改”,但这段代码以外仍可以修改它。

volatile const int a;

restrict

restrict用于修饰一个指针,表示“只能通过这个指针访问其变量”:

int ar[10];

int restrict *p1 = (int*)malloc(10*4);
int *p2 = ar;

p1指向的内存,肯定是只能通过p1访问的,所以可以添加restrict;但p2所指的内存,通过arp2都可以访问,所以不应添加restrict。另外,restrict不是标准,算是方言,所以不是所有地方都有,形式也不一定相同(也可能是__restrict等等)。

如果编译器知道restrict信息,就可以更好的优化,比如:

for (i=0; i<10; i++) {
p1[i] += 5;
p2[i] += 5;
ar[i] *= 2;
p2[i] += 5;
p1[i] += 5;
}

编译器知道p1[i]是独立的,所以它可以把两条p1有关的语句合成一条:

p1[i] += 10

而p2则显然不能替换,因为p2和ar是同一个值,替换了结果就错了。与votatile相反,默认情况下,编译器假设的是“最坏的情况”,不做任何优化。只有手动添加restrict后,才会认为变量唯一,可以选择捷径。

另一个典型例子是用于形参指针:

int f(int *p1, int *p2) {
*p1 = 10;
*p2 = 12;
return *p1;
}

这段函数的结构很简单,编译器能推断优化,直接返回10吗?不可以,因为如果p1和p2相等,返回值就是12。所以这个优化不能做;而如果你明知传入的p1和p2一定不相等,你就可以在形参列表里加上限制,如此一来,编译器就知道p1和p2一定指向两个变量,大胆的优化。

int f(restrict int *p1, restrict int *p2) {
*p1 = 10;
*p2 = 12;
return *p1; // 大胆优化为10
}

另一个经典例子是memcpy和memmove函数的声明:

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()没有这样的要求。所以第一个函数声明为restrict说明两个指针是访问到相应数据的唯一方式,而第二个没有,他允许拷贝的区间有重叠。

当你使用了restrict,就等于说明“只能通过这个指针访问其区域”,编译器会按照这个方式优化,你仍然可以调用相同的重叠参数传入,但会得到错误的结果(比如上面的f)。

C/C++ volatile restrict 用法的更多相关文章

  1. volatile的用法

    在再有人问你Java内存模型是什么,就把这篇文章发给他中我们曾经介绍过,Java语言为了解决并发编程中存在的原子性.可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如synchronized ...

  2. const修饰指针+volatile +restrict

    const这块的难点 const修饰指针有以下的几种形式 ,不同的形式 它的意义不一样. 形式1: int a=23: const int *p=&a: a是int型,&a是int * ...

  3. Java volatile的用法---转载

    我们知道,在Java中设置变量值的操作,除了long和double类型的变量外都是原子操作,也就是说,对于变量值的简单读写操作没有必要进行同步. 这在JVM 1.2之前,Java的内存模型实现总是从主 ...

  4. C#中volatile的用法

    恐怕比较一下volatile和synchronized的不同是最容易解释清楚的.volatile是变量修饰符,而synchronized则作用于一段代码或方法:看如下三句get代码: int i1;  ...

  5. KEIL里 Volatile的用法

    volatile用于防止相关变量被优化. 例如对外部寄存器的读写.对有些外部设备的寄存器来说,读写操作可能都会引发一定硬件操作,但是如果不加volatile,编译器会把这些寄存器作为普通变量处理,例如 ...

  6. static与volatile的用法

      static 1.概述 static 声明的变量在C语言中有两方面的特征: 1).变量会被放在程序的全局存储区中,这样可以在下一次调用的时候还可以保持原来的赋值.这一点是它与堆栈变量和堆变量的区别 ...

  7. java并发:线程同步机制之Volatile关键字&原子操作Atomic

    volatile关键字 volatile是一个特殊的修饰符,只有成员变量才能使用它,与Synchronized及ReentrantLock等提供的互斥相比,Synchronized保证了Synchro ...

  8. c语言,volatile

          一.意义: 该关键字的意义就是表示定义的变量值随时都会改变,必须从变量的地址处读取值,所以只有这个变量在使用过程中可能被改变(比如中断程序),就需要用这个关键字说明. )volatile, ...

  9. 再有人问你volatile是什么,把这篇文章也发给他

    在上一篇文章中,我们围绕volatile关键字做了很多阐述,主要介绍了volatile的用法.原理以及特性.在上一篇文章中,我提到过:volatile只能保证可见性和有序性,无法保证原子性.关于这部分 ...

  10. 深入理解Java中的volatile关键字

    在再有人问你Java内存模型是什么,就把这篇文章发给他中我们曾经介绍过,Java语言为了解决并发编程中存在的原子性.可见性和有序性问题,提供了一系列和并发处理相关的关键字,比如synchronized ...

随机推荐

  1. 说说"铁马冰河"事件

    地址: https://baike.baidu.com/item/%E9%93%81%E9%A9%AC%E5%86%B0%E6%B2%B3/60313943?fr=aladdin 其实也没有什么好说的 ...

  2. 2021 CCPC 哈尔滨

    gym 开场 zsy 签了 J,gjk 签了 B,我读错了 E 的题意,gjk 读对后过了 zsy 读了 K 给我,我记得是模拟赛原题,跟欧拉定理有关,但很难.他俩过了 D I,我大概会了 G 但不会 ...

  3. 使用 prerenderRoutes 进行预渲染路由

    title: 使用 prerenderRoutes 进行预渲染路由 date: 2024/8/20 updated: 2024/8/20 author: cmdragon excerpt: prere ...

  4. JavaScript设计模式样例二十一 —— 解释器模式

    解释器模式(Interpreter Pattern) 定义:提供了评估语言的语法或表达式的方式.目的:对于一些固定文法构建一个解释句子的解释器.场景:编译器.运算表达式计算. // 定义对于语法的断言 ...

  5. Element ui 动态自定义表格单元格样式

    最终实现效果 在Element UI 的文档中提到了用cell-style 方法来自定义单元格样式: 具体使用方法: 1. 在el-table 标签中添加 cell-style 绑定的自定义方法 2. ...

  6. 将.gradle下的 带hash名称文件夹中的依赖 转换为 .m2上的依赖

    背景:  android studio 在无法下载依赖的情况下 , 仅 使用 mavenLocal() 本地 .gradle 下有对应依赖 , .m2下没有 故将.gradle下的 带hash名称文件 ...

  7. HttpContext.SignInAsync 失效(表面解决了问题,未深入到.net core 源码去找问题,记录一下,等有时间翻一下.net core 源码试试能不能找到根本原因)

    今天在弄 identityServer4 项目的时候,发现好好的登录竟然没用了. 各种跟踪后发现是 HttpContext.SignInAsync 这个方法不写cookies了 原本经过这个方法后,会 ...

  8. 【YashanDB知识库】ODBC驱动类问题定位方法

    [标题]ODBC驱动类问题定位方法 [需求分类]故障分析 [关键字]ODBC [需求描述]由于我们的ODBC接口目前尚不完善,经常会遇见ODBC接口能力不足导致应用功能无法运行的问题,需要定位手段确定 ...

  9. Vue.js 异步组件传参

    本文主要展示一下如何给异步组件进行参数传递: 通过 h 函数就可以啦 versions: vue@3.2.13 子组件 Async.vue <template> <div> & ...

  10. manim边学边做--常用多边形

    多边形是常见的几何结构,它的形状看似千变万化,其实都可以由几种常用的多边形组合而成. 本篇介绍manim中提供的几个绘制常用多边形的模块. Triangle:等边三角形 Square:正方形 Rect ...