[转]Restrict关键字_weixin_33713350的博客-程序员宅基地

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

 

转载于:https://www.cnblogs.com/wlzy/p/10547038.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_33713350/article/details/93186933

智能推荐

线代笔记 #04# 线性变换_bangtuo9862的博客-程序员宅基地

源:线性代数的本质1、如何用数字描述向量每当我们用数字描述向量,都依赖于我们正在使用的基有了基之后,如何用数字刻画一个向量呢?例如说,我们用 i 帽和 j 帽线性组合得得一个向量 v , v = x * i + y * j只需要取出 i 帽和 j 帽前面的参数 x 和 y,就可以在该基下唯一确定一个向量 v换句话话说, v 是该基下 x 和 ...

Struts笔记_Jinggg_的博客-程序员宅基地

Struts笔记第一个struts name="domain":包名;namespace="/test":该包的名称空间,一般是以"/"开头;extends="struts-default" :继承的父包的名称;method="showHello" :JavaBean中对应处理的方法。(无参的);name="success" :动作方法返回的字符串;name

FLASH位宽为8、16、32时,CPU与外设之间地址线的连接方法_liuqiang_mail的博客-程序员宅基地

FLASH连接CPU时,根据不同的数据宽度,比如16位的NOR FLASH (A0-A19),处理器的地址线要(A1-A20)左移偏1位。为什么要偏1位?从软件和CPU的角度而言,一个地址对应一个字节,就是8位数据。这是肯定的,不要怀疑这点。对于具体器件而言,它的位宽是一定的,所谓位宽,指的是\"读/写操作时,最小的数据单元\" --别说最小单元是\"位\",一般设备上没有单独

[Azure]使用Powershell获取ASM和ARM存储的实际使用量_远行的风的博客-程序员宅基地

在下面两篇的基础上修改了一点脚本,加入了统计Blob实际大小的部分:http://blog.csdn.net/qwertyupoiuytr/article/details/77527998http://blog.csdn.net/qwertyupoiuytr/article/details/77527951针对ASM下存储账号的脚本:param( [Pa

使用ajax实现查询天气_你学狗狗叫的博客-程序员宅基地

使用ajax实现查询天气之前做的项目,发布到网上,如果有一样的,那应该是巧合吧代码块&amp;lt;html&amp;gt;&amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt; &amp;lt;title&amp;gt;天气预报&amp;lt;/title&amp;gt; &amp;lt;script type=&quot;text/javascript&quot; src=&quot;js/jquery-3.

随便推点

2019亚太内容分发大会,阿里云获CDN领袖奖、技术突破奖_m0_45510483的博客-程序员宅基地

近日,亚太CDN产业联盟主办的2019亚太内容分发大会在上海召开。本次大会以"5G分发"为主题,集结了CDN领域近千名行业领袖、专家参与。在会上,阿里云斩获“CDN领袖奖”、“技术突破奖”两项大奖。阿里云CDN于2014年正式商业化,在行业率先推出“按需购买、按量付费、一键配置”的云CDN模式,打破传统CDN不透明的市场格局,引领了行业变革。之后,阿里云CDN通过几轮近乎疯狂的降价,腰斩国内C...

Android中使用ViewFlipper实现屏幕页面切换(关于坐标轴的问题已补充更改)_weixin_30593443的博客-程序员宅基地

屏幕切换指的是在同一个Activity内屏幕间的切换,ViewFlipper继承了Framelayout类,ViewAnimator类的作用是为FrameLayout里面的View切换提供动画效果。如下动图:该类有如下几个和动画相关的函数:setInAnimation:设置View进入屏幕时候使用的动画,该函数有两个版本,一个接受单个参数,类型为android.view.an...

安卓模拟器速度慢的解决方法_silenceburn的博客-程序员宅基地_模拟器网速慢怎么办

<br /> 1.使用UBUNTU<br /> <br />以下是我测试helloWorld的结果,均是在打开boot animation的情况下<br />我机器的配置是 P6100 2G DDR3<br /> <br />WINDOWS XP SP2 <br />[2010-10-26 21:35:28 - HelloAndroid] ------------------------------[2010-10-26 21:35:28 - HelloAndroid] Android Launch!

用户空间和内核空间通讯之【Netlink 上】_christian513的博客-程序员宅基地

引言         Alan Cox在内核1.3版本的开发阶段最先引入了Netlink,刚开始时Netlink是以字符驱动接口的方式提供内核与用户空间的双向数据通信;随后,在2.1内核开发过程中,Alexey Kuznetsov将Netlink改写成一个更加灵活、且易于扩展的基于消息通信接口,并将其应用到高级路由子系统的基础框架里。自那时起,Netlink就成了Linux内核子系统和用户态的

Android Mms 接收信息流程_weixin_33774308的博客-程序员宅基地

信息的接收工作是由底层来完成的,当有一个 新的信息时底层完成接收后会以Intent的方式来通知上层应用,信息的相关内容也包含在Intent当中,Android所支持的信息Intent都定 义在android.provider.Telephony.Intents里面。短信的接收短信接收,对于上层应用程序来讲就是要处理广播事件SMS_RECEIVED_ACTION,它是由Framewo...

mysql 两表联合排序_mysql多个表联合排序_林忆酒的博客-程序员宅基地

开发过程中遇到个mysql的问题,我有多个表,多个表之间有联系,每个表都有单独的排序。course &gt; course_level &gt; course_unit &gt; course_lesson,这四个表的层级关系就是课程下面很多level,每个level下面有多个unit,每个unit下面有多个lesson,所有表的排序字段均为sort,全部是按照升序排列,如果某个级别sort相同,...

推荐文章

热门文章

相关标签