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.youkuaiyun.com/nathan_wz/article/details/8274451

[1] http://en.cppreference.com/w/c/language/restrict

<think>好的,用户想知道C++是否支持restrict关键字。首先,我需要回忆一下C和C++的关键字差异。记得在C语言中,restrict是C99标准引入的,用于指针优化,告诉编译器指针是唯一访问该数据的方式。而C++的标准中好像没有这个关键字。不过,很多编译器比如GCC和Clang可能以扩展形式支持,比如使用__restrict__或者__restrict。需要确认不同编译器的具体实现。 然后,用户可能在使用C++时遇到了需要优化指针的情况,或者从C代码移植过来,所以想知道在C++中如何处理。需要解释标准不支持,但编译器可能有扩展。还要注意C++的替代方法,比如使用引用或STL容器来避免指针别名问题。 另外,用户提供的引用内容提到C++编译器可能支持,因为很多同时是C编译器。这点需要强调,比如MSVC的__restrict,GCC的__restrict__。同时,C++11及以后的标准是否有变化?目前了解是没有,但最好确认最新标准。 最后,用户可能需要示例代码,说明如何在C++中使用这些扩展,以及何时使用它们合适。要提醒用户注意可移植性问题,因为不同编译器的支持可能不同。总结回答时要分点,结构清晰,涵盖标准情况、编译器扩展、替代方案和使用建议。</think>关于C++是否支持`restrict`关键字的解答: ### 核心结论 1. **C++标准不支持`restrict`** C++标准(包括C++11/14/17/20)未将`restrict`作为关键字引入,这与C语言的C99标准不同[^1]。 2. **编译器提供的扩展支持** 主流编译器通过非标准扩展实现类似功能: - **GCC/Clang**: 使用`__restrict__` ```cpp void func(int* __restrict__ a, int* __restrict__ b); ``` - **MSVC**: 使用`__restrict` ```cpp void func(int* __restrict a, int* __restrict b); ``` 3. **应用场景与作用**关键字向编译器承诺:指针指向的内存区域不存在数据重叠,帮助编译器进行激进的优化(如指令重排、循环展开),常见于数值计算、图像处理等高性能代码中。 4. **C++的替代方案** - 使用引用替代指针(天然具备非别名特性) - 使用`std::vector`等容器管理数据 - 利用`#pragma`指令进行局部优化提示 ### 代码示例对比 ```cpp // C语言示例(C99标准) void c_func(int* restrict a, int* restrict b); // C++示例(GCC扩展) void cpp_func(int* __restrict__ a, int* __restrict__ b); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值