当前位置:嗨网首页>书籍在线阅读

24-restrict类型限定符

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

12.5.3  restrict 类型限定符

restrict 关键字允许编译器优化某部分代码以更好地支持计算。它只能用于指针,表明该指针是访问数据对象的唯一且初始的方式。要弄明白为什么这样做有用,先看几个例子。考虑下面的代码:

int ar[10];
int * restrict restar = (int *) malloc(10 * sizeof(int));
int * par = ar;

这里,指针 restar 是访问由 malloc() 所分配内存的唯一且初始的方式。因此,可以用 restrict 关键字限定它。而指针 par 既不是访问 ar 数组中数据的初始方式,也不是唯一方式。所以不用把它设置为 restrict

现在考虑下面稍复杂的例子,其中 nint 类型:

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 相关的两条语句替换成下面的语句,将导致计算错误:

par[n] += 8; / * 给出错误的结果 */

这是因为 for 循环在 par 两次访问相同的数据之间,用 ar 改变了该数据的值。

在本例中,如果未使用 restrict 关键字,编译器就必须假设最坏的情况(即,在两次使用指针之间,其他的标识符可能已经改变了数据)。如果用了 restrict 关键字,编译器就可以选择捷径优化计算。

restrict 限定符还可用于函数形参中的指针。这意味着编译器可以假定在函数体内其他标识符不会修改该指针指向的数据,而且编译器可以尝试对其优化,使其不做别的用途。例如,C库有两个函数用于把一个位置上的字节拷贝到另一个位置。在C99中,这两个函数的原型是:

void * memcpy(void * restrict s1, const void * restrict s2, size_t n);
void * memmove(void * s1, const void * s2, size_t n);

这两个函数都从位置 s2n 字节拷贝到位置 s1memcpy() 函数要求两个位置不重叠,但是 memmove() 没有这样的要求。声明 s1s2restrict 说明这两个指针都是访问相应数据的唯一方式,所以它们不能访问相同块的数据。这满足了 memcpy() 无重叠的要求。 memmove() 函数允许重叠,它在拷贝数据时不得不更小心,以防在使用数据之前就先覆盖了数据。

restrict 关键字有两个读者。一个是编译器,该关键字告知编译器可以自由假定一些优化方案。另一个读者是用户,该关键字告知用户要使用满足 restrict 要求的参数。总而言之,编译器不会检查用户是否遵循这一限制,但是无视它后果自负。