[转]Restrict关键字
0 定义
C99中新增加的用于修饰指针的关键字,用于表示该指针所指向的内存,只有通过该指针访问得到(如下ptr指向的内存单元只能通过ptr访问得到)。从而可以让编译器对代码进行优化,生成更有效率的汇编代码。
char *restrict ptr;
1 优化举例
举例1,如下代码(引自参考1),以及翻译成汇编之后的代码。
#include <stdio.h> #ifdefRES
void multi_add(int* restrict p1, int* restrict p2, int* restrict pi)
#else
void multi_add(int* p1, int* p2, int* pi)
#endif {
*p1+= *pi;
*p2+= *pi;
} int main()
{
int a =1, b = 2;
int inc =1;
// increase both aand b by 1
multi_add(&a,&b, &inc);
// print the result
printf("a= %d, b = %d\n", a, b); }
调用mulit_add函数时,翻译成汇编后的代码,如果是没有RES,则是
mov(%rdx),%eax
add%eax, (%rdi)
mov(%rdx),%eax
add%eax, (%rsi)
相反如果有RES定义,则是
mov(%rdx),%eax
add %eax,(%rdi)
add %eax,(%rsi)
因为pi是由restrict关键字修饰的,所以认为pi所指向的内存只可能通过pi访问,不可能其它 alias能访问到。所以没有必要每次都mov操作。
举例2
int ar[10];
int *restrict restar =(int *)malloc(10* sizeof(int));
int *par =ar; for (n =0; n< 10; n++)
{
par[n]+= 5;
restar[n]+= 5;
ar[n]*= 2;
par[n]+= 3;
restar[n]+= 3;
}
同样由于restar 是用restrict修饰的,所以编译器会优化成restar[n] += 8;
其实优化的本质上就是使用了一系列这寄存器,而传统架构上的使用Cache(可以参见https://www.zhihu.com/question/41653775)。
2 使用举例
用restrict修饰的指针,最多的是用来作为参数、memcpy中的src和dst就是使用restrict修改的,所以个人总结出来的用途主要在于copy操作过程中,不用每个字节每个字节去取址计算操作,而是直接page操作的可能。大大提升了性能。
3 注意点
首先,有可能反汇编后的代码,并不能达到遇期的优化效果,这是因为gcc中指定的优化等级不对,或者根本没有指定优化等级。所以为了让编译器识别并优化restrict关键字,必须编译时指定优化等级。如在1中的举例,如果multi_add(&a,&b,&a);调用,那么在不同等级优化下的效果,如下表所示。
| 优化等级 | 最终值 | 原因 |
| 不优化 | a = 2; b = 4; | Gcc在没有开-O优化时是不会对restrict关键字优化 |
| -O1 | A=2;b=3; | restrict关键字的优化 |
| -O2及以上 | a=2;b=4; | Multi_add函数不再被main调用 |
然后,restrict关键字,不仅是告诉编译器优化代码,而且还对使用者(程序员)提出了要求,即必须保证restrict指针指向的内存,只能通过该指针访问。(记住这点是要求程序员的,编译器无法识别出报warning之类的信息)。因此,如下的代码,都可能是有问题的。
float x[100];
float *c;
void f(int n, float *restrict a, float *const b){
int i;
for (i =0; i < n; i++)
a[i]= b[i]+ c[i];
} void g3(void){
float d[100],e[100];
c =x; f(100,d, e);// OK
f(50,d, d +50); // OK
f(99,d + 1, d);// undefined behavior
c =d; f(99,d + 1, e);// undefined behavior
f(99,e, d +1); //
最后,restrict的指针不能赋值给另一个restrict的指针,如下。但是,restrict的指针可以赋值给一个非restrict的指针。
int* restrict p1 =&a;
int* restrict p2 =&b;
p1 =p2; //undefined behavio void f(int n, float *restrict r, float *restrict s){
float *p = r,*q = s; //OK
while (n--> 0) *p++ = *q++;// almost certainly optimized just like *r++= *s++
}
4 参考文献
[0] http://blog.csdn.net/nathan_wz/article/details/8274451
[1] http://en.cppreference.com/w/c/language/restrict
[转]Restrict关键字的更多相关文章
- restrict关键字(暗示编译器,某个指针指向的空间,只能从该指针访问)
我们希望某个对象(内存空间)不被修改的通常做法是什么?声明该空间的const类型,但是这样真的可以吗?是不是的,由于const空间对象的指针是可以付给一个非const值指针的.所以这仍然无法不让该空间 ...
- c99标准的restrict关键字
参考自restrict restrict解释 restrict关键字出现于C99标准,wiki上的解释restrict from wiki. In the C programming language ...
- [转] restrict关键字用法
PS: 在函数中,指针参数指定了restrict,表示这个指针指向的这段区域只能通过这个指针修改 c99中新增加了一个类型定义,就是restrict. 看了下网上的相关贴子,但还是问题解决的不够.下面 ...
- restrict关键字
值得注意的是,一旦你决定使用restrict来修饰指针,你必须得保证它们之间不会互相重叠,编译器不会替你检查. 关键字restrict有两个读者.一个是编译器,它告诉编译器可以自由地做一些有关优化的假 ...
- C 语言restrict 关键字的概念及使用例子
restrict是c99标准引入的,它只可以用于限定和约束指针,并表明指针是访问一个数据对象的唯一且初始的方式.即它告诉编译器,所有修改该指针所指向内存中内容的操作都必须通过该指针来修改,而不能通过其 ...
- C语言restrict关键字的使用----可以用来优化代码
C99中新增加了restrict修饰的指针:由restrict修饰的指针是最初唯一对指针所指向的对象进行存取的方法,仅当第二个指针基于第一个时,才能对对象进行存取.对对象的存取都限定于基于由restr ...
- DSP 中关键字extern,cregister,Near ,Far,restrict,volatile
extern:extern可以置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.另外,extern也可用来进行链接指定. const: 可以 ...
- c/c++常用的几个关键字总结
一.volatile volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据.如果没有volatile关键字,则编 ...
- ”危险“的restrict与GCC的编译优化
restrict是C99标准中新添加的关键字,对于从C89标准开始起步学习C语言的同学来说(包括我),第一次看到restrict还是相当陌生的.Wikipedia给出的解释如下: In the C p ...
随机推荐
- "学霸"系统Alpha版本发布说明
一.版本功能 我们的软件为学霸app,目标功能为:北航校内学子的类“知乎”应用,可以实现用户的管理.提问.回答.搜索.上传.下载以及交互:当前版本主要实现功能为:用户的管理.提问.回答已经交互. 一下 ...
- Day Three
站立式会议 站立式会议内容总结 442 今天:从本地导入电子书页面编写以及部分逻辑代码 遇到的问题:界面适配问题 明天:具体计划界面的编写,解决上面问题 331 今天:监听webview滑动底端事件 ...
- Window环境下RabbitMQ 添加用户、设置角色和权限
基本上新增用户.角色和权限的方法都一样,大概如下: REM 添加一个帐号 密码 rabbitmqctl.bat add_user zhangfujun zhangfujun123 REM 添加角色 r ...
- Jmeter当获取正则表达式匹配数字为负数时获取所有匹配的值
需求说明:如果http的bodyData中有类似于{"idList":["6505","6506","2222".... ...
- js用currentStyle和getComputedStyle获取css样式(非行间) 兼容ie与火狐
用js的style属性可以获得html标签的样式,但是不能获取非行间样式.那么怎么用js获取css的非行间样式呢?在IE下可以用currentStyle,而在火狐下面我们需要用到getComputed ...
- BeanFactory 简介以及它 和FactoryBean的区别(阿里面试)
BeanFacotry是spring中比较原始的Factory.如XMLBeanFactory就是一种典型的BeanFactory.原始的BeanFactory无法支持spring的许多插件,如AOP ...
- luogu1312
有趣的题面 超有趣的dfs大模拟,码了巨久,卡时过了此题qaq #include <cstdio> #include <cstring> #include <algori ...
- JDK8新特性,方法的引用
引用方法并运行 在Java中,方法和构造方法都看作是对象的一种,那么你要引用它(不是调用),则可以用::来引用.用来存储这个引用的类型用@FunctionlaInterface注解来标识. 示例: p ...
- 洛谷 P1437 [HNOI2004]敲砖块 解题报告
P1437 [HNOI2004]敲砖块 题目描述 在一个凹槽中放置了 n 层砖块.最上面的一层有n 块砖,从上到下每层依次减少一块砖.每块砖 都有一个分值,敲掉这块砖就能得到相应的分值,如下所示. 1 ...
- 解题:BZOJ 2989 数列
题面 学习二进制分组 题目本身可以看成二维平面上的问题,转成切比雪夫距离后就是矩形和了 二进制分组是将每个修改添加到末尾,然后从后往前二进制下进位合并,这样最多同时有$\log n$组,每个修改只会被 ...