考虑这两个功能:
void foo(char * __restrict localPtr)
{
// some work with localPtr
}
void bar(char * __restrict ptr)
{
// some work with ptr
foo(_ptr);
// some other work with ptr
}
ptr
中__restrict
被bar
声明为foo()
,是否正在调用localPtr
危险?危险,我的意思是ptr
指向的记忆区域与{{1}}重叠。有关这方面的指导原则是什么?
答案 0 :(得分:2)
restrict
限定符意味着被调用函数访问在localPtr
中作为foo
传递的内存的唯一方法是通过该指针;那个记忆没有别名。这可能使优化器能够生成更好的代码,因为它不必担心另一个指针也会改变数据。
在这种情况下,以及在大多数其他情况下,restrict
限定符会对您(程序员进行调用)造成责任,以确保您遵守“无别名”要求。
上述代码没有明显的危险。
请注意,在使用restrict
时,通常在参数列表中有多个指针。从C标准来看,比较:
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
void *memmove(void *s1, const void *s2, size_t n);
第一个(memcpy()
)表示内存块[s1 .. s1+n-1]
和[s2 .. s2+n-1]
不得重叠;如果事实上重叠,你会得到未定义的行为。第二个(memmove()
)没有强制要求。
但不是调用
foo()
创建另一个正在更改数据的指针吗?
是,否,排序......但主要是否。
foo()
中的指针肯定会传递给bar()
,但当bar()
正在运行时,bar()
获取内存的唯一方法是通过指针通过。因此,bar()
能够在假设它没有与其正在使用的内存的别名的情况下进行编译。
当编译器正在处理foo()
时,它知道(确保)在bar()
的参数被评估之后且在函数被调用之前存在一个序列点,而另一个在函数返回时。它知道数据可能已由bar()
修改,因为它未通过const char *
。因此,它将生成代码以解释这些可能性。但是,编译器也知道foo()
访问localPtr
所解决的内存的唯一方法是通过localPtr
(这就是restrict
所说的),它可以继续基于这个假设。
因此,在调用bar()
时会有第二个指针副本,但它不会以任何方式违反restrict
的规则。