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. AI大模型 —— 国产大模型 —— 华为大模型

    有这么一句话,那就是AI大模型分两种,一种是大模型:另一种是华为大模型. 如果从技术角度来分析,华为的技术不论是在软件还是硬件都比国外的大公司差距极大,甚至有些技术评论者认为华为的软硬件技术至少落后2 ...

  2. 【故障排查】10分钟解决Quartz重复调度的疑难杂症

    我司使用Apache DolphinScheduler作为调度框架很久了,感兴趣的小伙伴可以看看这些干货文章: 因为之前监控到会出现重复的调度的问题,所以此文记录排查重复调度问题的全过程,希望对社区其 ...

  3. 从网友探秘 《黑神话:悟空》 的脚本说说C#

    <黑神话:悟空>千呼万唤始出来.在正式发售后不到24小时,Steam在线玩家峰值突破222万,在Steam所有游戏在线玩家历史峰值中排名第二.第一拨玩家纷纷晒出好评,称这款现象级产品正式开 ...

  4. 2024-08-28:用go语言,给定一个从1开始、长度为n的整数数组nums,定义一个函数greaterCount(arr, val)可以返回数组arr中大于val的元素数量。 按照以下规则进行n次

    2024-08-28:用go语言,给定一个从1开始.长度为n的整数数组nums,定义一个函数greaterCount(arr, val)可以返回数组arr中大于val的元素数量. 按照以下规则进行n次 ...

  5. Kubernetes-19:Prometheus-operator集群监控神器

    Prometheus-operator集群监控 github地址:https://github.com/prometheus-operator/kube-prometheus 具体的Prometheu ...

  6. Android 执行shell命令 非root

    一个开源的项目已经完成了这个功能 app_process-shell-use,这个项目网上讲解的,很多,我这边就把操作时一些简要步骤说明一下 但是该方式有缺点:必须要先USB连接,debug的时候,运 ...

  7. docker image 变小的办法

    https://www.docker.com/blog/intro-guide-to-dockerfile-best-practices/ https://medium.com/sciforce/st ...

  8. sicp每日一题[2.1]

    Exercise 2.1 Exercise 2.1: Define a better version of make-rat that handles both positive and negati ...

  9. net core中byte数组如何高效转换为16进制字符串

    在 .NET Core 中,如何把 byte[] 转换为 16 进制字符串?你能想到哪些方法?什么方式性能最好?今天和大家分享几种转换方式. 往往在处理字符串性能问题时,首先应该想到的是怎么想办法减少 ...

  10. Failed to convert value of type 'java.lang.String' to required type

    DEBUG 微信小程序Java后台 Failed to convert value of type 'java.lang.String' to required type 产生这种条件的原因一般是使用 ...