【C】C99 restrict 关键字
restrict是C99引入的关键字,该关键字适用于指针的声明,并表明指针是访问一个数据对象的唯一且初始的方式,由此编译器可以进行一些优化。
例1
搞自:http://www.blogjava.net/killme2008/archive/2007/08/04/134399.html
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进行了改变。使用了关键字restric,编译器就可以放心地进行优化了。
例2
参考:http://en.wikipedia.org/wiki/Restrict
考虑下面两个函数: test.c
void fun1(size_t *pa, size_t *pb, size_t *pc)
{
*pc += *pa;
*pb += *pa;
}
void fun2(size_t *restrict pa, size_t *restrict pb, size_t *restrict pc)
{
*pc += *pa;
*pb += *pa;
}
gcc -S -std=c99 -O2 test.c 查看其汇编源码,经分析可以发现fun2比fun1少执行一条汇编语句,从而实现优化。
fun1:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
movl 16(%ebp), %ecx
movl 12(%ebp), %eax
pushl %ebx
movl (%edx), %ebx ;此时edx保存的是pa的值,此句执行结果是把pa指针指向的值存放在ebx中
addl %ebx, (%ecx) ;ecx保存的是pc的值,把ebx的值加到pc指向的地址中
movl (%edx), %edx ;把pa解引用后的值保存在edx中
addl %edx, (%eax) ;eax保存的是pb的值,把edx的值加到pb指向的地址中
;; 如果我们可以确保ebx的值没有发生改变,我们完全可以省去movl (%edx), %edx,并修改addl %edx, (%eax)为addl %ebx, (%eax),从而提高效率。
;; 但编译器没有这么做,因为有可能pa和pc指向同一块内存区域,修改pc的值有可能修改pa的值,所以要必须重新载入pa指向的值
popl %ebx
popl %ebp
ret
.size fun1, .-fun1
.p2align 4,,15
.globl fun2
.type fun2, @function
fun2:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
movl 16(%ebp), %ecx
movl 12(%ebp), %eax
movl (%edx), %edx
addl %edx, (%ecx)
addl %edx, (%eax)
;; 使用restrict关键字后,编译器就知道pa,pb,pc指向不同的内存区域(至于是否真正指向不同的区域需要程序员来保证),修改pc的值不会影响pa的值,所以edx的值没有改变,还可以继续使用,从而减少一条汇编语句
popl %ebp
ret
.size fun2, .-fun2
.p2align 4,,15
作者:visayafan
出处:http://www.cnblogs.com/visayafan/
本博客文章欢迎转载,转载时请注意标明出处。