0 定义
C99中新增加的用于修饰指针的关键字,用于表示该指针所指向的内存,只有通过该指针访问得到(如下ptr指向的内存单元只能通过ptr访问得到)。从而可以让编译器对代码进行优化,生成更有效率的汇编代码。
char *restrict
ptr;
1 优化举例
举例1,如下代码(引自参考1),以及翻译成汇编之后的代码。
#include
#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
",
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