Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1798330
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: C/C++

2012-04-24 18:33:32

很多文章都大致说出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的用法和含义已经非常清晰了。


阅读(1603) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~