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. 电视家APP会员退款了 —— 网络电视APP的合规性处理

    今天打开家里网络电视的时候突然发现"电视家APP"居然无法使用了,随后发现账户关联的银行卡收到退款了,于是好奇的研究了一下这个事情. 由于家里是在农村,闭路电视的图像效果很差,估计 ...

  2. [考试记录] 2024.8.10 csp-s 模拟赛18

    80 + 20 + 0 + 70 = 170 第三题应该有 10 分暴力的,但我没打. T1 星际旅行 题面翻译 总共有n个节点,m条路径,要求其中m-2条路径走两遍,剩下2条路径仅走一遍,问不同的路 ...

  3. 使用Django-Channels实现websocket通信+大模型对话

    前言 最近一直在做这个大模型项目,我选了 Django 作为框架(现在很多大模型应用都用的 FastAPI,不过我已经用习惯 Django 了) 之前使用 AspNetCore 作为后端的时候,我先后 ...

  4. Kruskal和Prim模板

    例题:P3366 [模板]最小生成树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) Kruskal #include <bits/stdc++.h> #define d ...

  5. AvaloniaChat-v0.0.2:兼容智谱AI 快速使用指南

    智谱AI介绍 北京智谱华章科技有限公司(简称"智谱AI")致力于打造新一代认知智能大模型,专注于做大模型的中国创新.公司合作研发了中英双语千亿级超大规模预训练模型GLM-130B, ...

  6. ios滚动列表白屏问题

    移动端分页列表,在ios上滚动加载分页时候,使用scrollTop,会引起白屏问题. 看不少文章说是使用了-webkit-overflow-scrolling: touch;引起的硬件加速问题.亲测删 ...

  7. One-for-All:上交大提出视觉推理的符号化与逻辑推理分离的新范式 | ECCV 2024

    通过对多样化基准的严格评估,论文展示了现有特定方法在实现跨领域推理以及其偏向于数据偏差拟合方面的缺陷.从两阶段的视角重新审视视觉推理:(1)符号化和(2)基于符号或其表示的逻辑推理,发现推理阶段比符号 ...

  8. 【selenium + python】之BSTestRunner生成测试报告时报错:NameError: name 'unicode' is not defined

    好久没生成报告了,最近使用的时候报了一个错误!用的这个报告模板BSTestRunner但是汇报下面的错误: NameError: name 'unicode' is not defined 经查询得知 ...

  9. shiro的rememberMe各种漏洞一刀切解决

    rememberMe的低版本AES固定密码导致的漏洞,高版本仍然有被爆破,穷举的风险等.这种东西总是在安全检测的时候被拿出来说事儿,然而项目中并未开启rememberMe,也就是说压根不需要这个功能. ...

  10. python 读取mysqlDB中指定的表名的DDL语句

    注意: 1. 此python文件不要起名为mysql,会跟import的包名重复,python mysql.py运行报错 2.如果需要带端口号,请加database后加上, port="33 ...