我总是不确定,在C++中,restrict关键字是什么意思?
是否意味着赋予函数的两个或更多指针不重叠?还有什么意思?
我正在浏览一些文档和问题/答案,并看到它提到.我读了一个简短的描述,声明它基本上是程序员的承诺,指针不会用于指向其他地方.
任何人都可以提供一些现实案例,其值得实际使用吗?
有没有人见过任何关于restrictgcc/g ++实际使用C/C++ 关键字的数字/分析是否能在现实中提供任何显着的性能提升(而不仅仅是在理论上)?
我已经阅读了各种推荐/贬低其使用的文章,但我没有碰到任何实际数字,实际上证明了任何一方的论点.
编辑
我知道这restrict不是C++的正式部分,但它得到了一些编译器的支持,我读过Christer Ericson的一篇论文,强烈推荐使用它.
我知道restrictC中的限定符指定两个指针指向的内存区域不应重叠。据我了解,Linux(不是 SUS)原型看起来memcpy像 -
void* memcpy(void *restrict dest, const void *restrict src, size_t count);
Run Code Online (Sandbox Code Playgroud)
然而,当我查看man7.org/memcpy时,声明似乎是 -
void *memcpy(void dest[restrict .n], const void src[restrict .n], size_t n);
Run Code Online (Sandbox Code Playgroud)
我的问题是 -
.前面的是什么n意思?我熟悉可变长度数组声明。变量的 for是否.出现在数组指定之后?这是标准的一部分吗?标题说明了一切.我很好奇为什么restrict关键字不是C++的一部分?我对C++知之甚少,而且我仍然无法在网上找到任何阻止这种情况的理由.有没有人知道会发生什么可怕的事情,如果C++标准会像C一样使用这个关键字?它根本不需要吗?
更多解释:这不是关于使用它,也许在我的一生中我不会从这个关键字中获益.这个问题只是关于好奇心,因为自C99以来,限制是C的一部分,即15年.
阅读本文:我对技术原因感兴趣,而不是像"他们只是不喜欢,它不够酷"这样的意见
我restrict对此有一个大致的了解,但我希望澄清一些细节.我有一个函数从一个缓冲区读取一个以null结尾的字符串,并在另一个缓冲区中写出一个URL编码的版本.该函数具有此签名(当前没有restrict):
char const *StringUrlEncode(char const *unencoded,
char *encoded,
char *encodedEnd);
Run Code Online (Sandbox Code Playgroud)
unencoded是我的以null结尾的源字符串.目标缓冲区由encoded和表示encodedEnd,其中encoded指向char缓冲区encodedEnd中的第一个并指向缓冲区后的第一个字符,即函数将写入char但不包括指向的位置encodedEnd- 这是您的基本begin/ end迭代器如果您熟悉C++ STL约定,请配对.
如果我添加restrict到此函数,它应该只应用于前两个参数:
char const *StringUrlEncode(char const *restrict unencoded,
char *restrict encoded,
char *encodedEnd);
Run Code Online (Sandbox Code Playgroud)
或者通过将它添加到所有三个参数中我是否有一些好处?
我可以看到制作输入和输出缓冲区restrict有助于编译器知道它们不重叠.但是由于最后一个参数,encodedEnd仅用于标记输出缓冲区的结尾,我认为这restrict对编译器没有任何帮助(虽然我认为它不会受到伤害,除了添加不必要的噪声到函数声明).
只是想知道:当我向指针添加restrict时,我告诉编译器指针不是另一个指针的别名.我们假设我有一个类似的函数:
// Constructed example
void foo (float* result, const float* a, const float* b, const size_t size)
{
for (size_t i = 0; i < size; ++i)
{
result [i] = a [0] * b [i];
}
}
Run Code Online (Sandbox Code Playgroud)
如果编译器必须假设result可能重叠a,则必须每次重新获取.但是,正如a标记的那样const,编译器也可以假设a是固定的,因此一次取回它就可以了.
问题是,在这种情况下,使用restrict的推荐方法是什么?我当然不希望编译器a每次都重新获取,但我找不到关于如何restrict在这里工作的好信息.
该restrict关键字的行为在C99定义由6.7.3.1:
设D是普通标识符的声明,它提供了一种将对象P指定为类型T的限制限定指针的方法.
如果D出现在块内并且没有存储类extern,则让B表示该块.如果D出现在函数定义的参数声明列表中,则让B表示关联的块.否则,让B表示主块(或在独立环境中在程序启动时调用的任何函数块).
在下文中,指针表达式E被称为基于对象P if(在评估E之前执行B中的某个序列点)修改P以指向其先前指向的数组对象的副本将改变E.119的值)注意''based''仅为具有指针类型的表达式定义.
在每次执行B期间,让L为具有基于P的&L的任何左值.如果L用于访问它指定的对象X的值,并且X也被修改(通过任何方式),则以下要求适用:T不应该是const限定的.用于访问X值的每个其他左值也应具有基于P的地址.出于本子条款的目的,每次修改X的访问也应被视为修改P. 如果为P分配了指针表达式E的值,该指针表达式E基于与块B2相关联的另一个受限指针对象P2,则B2的执行应在执行B之前开始,或者B2的执行应在该执行之前结束.分配.如果不满足这些要求,则行为未定义.
就像其他人一样,我很难理解这个定义的所有复杂性.作为这个问题的答案,我希望看到第4段中每个要求违反要求的一些好例子.本文:
在"编译器可能假设......"方面做得很好.扩展该模式并将编译器可以做出的假设以及它们如何无法保持,每个示例都很棒.
通过使用这样的restrict关键字:
int f(int* restrict a, int* restrict b);
Run Code Online (Sandbox Code Playgroud)
我可以指示编译器数组a和b不重叠.说我有一个结构:
struct s{
(...)
int* ip;
};
Run Code Online (Sandbox Code Playgroud)
并编写一个带有两个struct s对象的函数:
int f2(struct s a, struct s b);
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我怎样才能类似地指示编译器a.ip并且b.ip不重叠?
int foo(void *restrict ptr1, void *restrict ptr2)
{
if (ptr1 == ptr2) {
return 1234;
} else {
return 4321;
}
}
Run Code Online (Sandbox Code Playgroud)
restrict意味着指针指向的内存没有被任何其他指针别名。鉴于此,thenptr1和ptr2不能指向同一区域,因此比较是同义反复,并且在所有情况下都foo()应该返回。4321
然而clang,gcc不要这样看(https://godbolt.org/z/fvPd4a1vd)。这是错过的优化还是有其他原因?
c c++ compiler-optimization language-lawyer restrict-qualifier