【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

 

 

 

你可能感兴趣的:(【C】C99 restrict 关键字)