当前位置:软件学习 > 其它软件 >>

C99的restrict关键字

很多文章都大致说出restrict的意思:它向编译器表达一种用于优化的意愿,即由restrict所修饰的指针所指的对象只会通过这个指针访问。然而好像极少会深入剖析这个概念的含义。

写两个相似的函数,唯一的区别在于restrict的修饰。
void
f1(int *restrict p1, int *restrict p2)
{
    for (int i = 0; i < 100; i++)
        *p1 += *p2;
}

void
f2(int *p1, int *p2)
{
    for (int i = 0; i < 100; i++)
        *p1 += *p2;
}

使用gcc的-O3(-O2也是一样的)选项来优化编译,可以得到:
f1(int *restrict p1, int *restrict p2):
movl    8(%esp), %edx
movl    4(%esp), %eax
imull    $100, (%edx), %edx
addl    %edx, (%eax)
ret

f2(int *p1, int *p2):
pushl    %ebx
movl    8(%esp), %ecx
movl    $100, %eax
.L3:
movl    12(%esp), %ebx
movl    (%ecx), %edx
addl    (%ebx), %edx
subl    $1, %eax
movl    %edx, (%ecx)
jne    .L3
popl    %ebx
ret

我高亮了两个函数进行*p1 += *p2的部分。f1里把*p2的值乘以100,再把它加到*p1上。而在f2里,*p2被按部就班地通过每次迭代里加到*p1上。可以看到,通过对restrict的优化,f1省略了函数的压栈和循环的代码。很明显,f1比f2高效地多。f1之所以会得到这样的优化,是因为它认为p1和p2所指的值是不同的,所以p1值的改变不会影响到p2。然而f2不敢作这样的假设。

但是,如果我们破坏restrict的规则,程序可能会出错。上面的程序不好测试,因为最后的和会很大,导致整型溢出,所以我举另一个例子:
void
f1(int *restrict ap1, int *restrict ap2)
{
    for (int i = 0; i < 100; i++)
        *ap1 = *ap2 + 1;
}

void
f2(int *bp1, int *bp2)
{
    for (int i = 0; i < 100; i++)
        *bp1 = *bp2 + 1;
}
产生的汇编代码为:
f1(int *restrict ap1, int *restrict ap2)
movl    8(%esp), %eax
movl    (%eax), %edx
movl    4(%esp), %eax
addl    $1, %edx
movl    %edx, (%eax)
ret

f2(int *bp1, int *bp2)
pushl    %ebx
movl    8(%esp), %ebx
movl    $100, %eax
movl    12(%esp), %ecx
.LVL3:
movl    (%ecx), %edx
addl    $1, %edx
subl    $1, %eax
movl    %edx, (%ebx)
jne    .L3
popl    %ebx
ret

测试代码:
int
main()
{
    int a = 1;
    int b = 1;
    f1(&a, &a);
    f2(&b, &b);

    printf("a: %d, b: %d\n", a, b);

    return 0;
}
输出为:a: 2, b: 101

至此,我想restrict的用法和含义已经非常清晰了。


摘自 技博控*淘米挣
补充:软件开发 , 其他 ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,