再议C语言(10)restrict关键字的作用
Posted 奇妙之二进制
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了再议C语言(10)restrict关键字的作用相关的知识,希望对你有一定的参考价值。
restrict是c99标准引入的,它只可以用于限定和约束指针,并表明指针是访问一个数据对象的唯一且初始的方式。即它告诉编译器,所有修改该指针所指向内存中内容的操作都必须通过该指针来修改,而不能通过其它途径(其它变量或指针)来修改;这样做的好处是,能帮助编译器进行更好的优化代码,生成更有效率的汇编代码.
restrict的出现是为了解决指针的一部分缺陷(功能强大,限制方法较少,使用过于自由),例如:两个指针指向同一块内存或者指向的内存存在重叠,编译器无法获知这些情况,为了保证程序运行的正确性,编译结果可能会多次读取同一地址内存,如下:
int foo(int *a, int *b)
*a = 5;
*b = 6;
return *a + *b;
* 如果a和b指向同一块内存,运行结果是12,如果是不同内存,运行结果是11,
编译器为了保证运行结果的正确性,就需要每次都从内存中读取.
考虑下面的例子:
int ar[10];
int * restrict restar=(int *)malloc(10*sizeof(int));
int *par=ar;
这里说明restar是访问由malloc()分配的内存的唯一且初始的方式。par就不是了。
那么:
for(n=0;n<10;n++)
par[n]+=5;
restar[n]+=5;
ar[n]*=2;
par[n]+=3;
restar[n]+=3;
因为restar是访问分配的内存的唯一且初始的方式,那么 编译器 可以将上述对restar的操作进行优化:
restar[n]+=8;
而par并不是访问数组 ar的唯一方式,因此并不能进行下面的优化:
par[n]+=8;
因为在par[n]+=3前,ar[n]*=2进行了改变。使用了 关键字 restrict,编译器就可以放心地进行优化了。
这个关键字据说来源于古老的FORTRAN。
C库中有两个函数可以从一个位置把字节复制到另一个位置。在C99标准下,它们的原型如下:
void * memcpy(void * restrict s1, const void * restrict s2, size_t n);
void * memove(void * s1, const void * s2, size_t n);
这两个函数均从s2指向的位置复制n字节数据到s1指向的位置,且均返回s1的值。两者之间的差别由关键字restrict造成,即memcpy()可以假定两个内存区域没有重叠。memmove()函数则不做这个假定,因此,复制过程类似于首先将所有字节复制到一个临时缓冲区,然后再复制到最终目的地。如果两个区域存在重叠时使用memcpy()会怎样?其行为是不可预知的,既可能正常工作,也可能失败。在不应该使用memcpy()时,编译器不会禁止使用memcpy()。因此,使用memcpy()时,您必须确保没有重叠区域。这是程序员的任务的一部分。
关键字restrict有两个读者。
- 一个是编译器,它告诉编译器可以自由地做一些有关优化的假定。
- 另一个读者是用户,他告诉用户仅使用满足restrict要求的参数。一般,编译器无法检查您是否遵循了这一限制,如果您蔑视它也就是在让自己冒险。
以上是关于再议C语言(10)restrict关键字的作用的主要内容,如果未能解决你的问题,请参考以下文章
精通C语言ANSI C 类型限定符const,volatile,restrict,_Atomic