为什么不执行__restrict__修饰符?

时间:2020-04-21 20:03:03

标签: c++ pass-by-reference restrict-qualifier

如果给函数参数添加了注释ERROR: Command errored out with exit status 1: command: /usr/local/bin/python3.6 /usr/local/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py prepare_metadata_for_build_wheel /tmp/tmplcfg2oqe cwd: /tmp/pip-install-o7_ciep3/PyQt5 Complete output (37 lines): Querying qmake about your Qt installation... /usr/bin/qmake -query Traceback (most recent call last): File "/usr/local/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 103, in prepare_metadata_for_build_wheel hook = backend.prepare_metadata_for_build_wheel AttributeError: module 'sipbuild.api' has no attribute 'prepare_metadata_for_build_wheel' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/usr/local/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 257, in <module> main() File "/usr/local/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 240, in main json_out['return_val'] = hook(**hook_input['kwargs']) File "/usr/local/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 108, in prepare_metadata_for_build_wheel config_settings) File "/usr/local/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py", line 136, in _get_wheel_metadata_from_wheel whl_basename = backend.build_wheel(metadata_directory, config_settings) File "/tmp/pip-build-env-h65hqnoo/overlay/lib/python3.6/site-packages/sipbuild/api.py", line 51, in build_wheel project = AbstractProject.bootstrap('pep517') File "/tmp/pip-build-env-h65hqnoo/overlay/lib/python3.6/site-packages/sipbuild/abstract_project.py", line 82, in bootstrap project.setup(pyproject, tool, tool_description) File "/tmp/pip-build-env-h65hqnoo/overlay/lib/python3.6/site-packages/sipbuild/project.py", line 410, in setup self.apply_user_defaults(tool) File "project.py", line 62, in apply_user_defaults super().apply_user_defaults(tool) File "/tmp/pip-build-env-h65hqnoo/overlay/lib/python3.6/site-packages/pyqtbuild/project.py", line 86, in apply_user_defaults super().apply_user_defaults(tool) File "/tmp/pip-build-env-h65hqnoo/overlay/lib/python3.6/site-packages/sipbuild/project.py", line 215, in apply_user_defaults self.builder.apply_user_defaults(tool) File "/tmp/pip-build-env-h65hqnoo/overlay/lib/python3.6/site-packages/pyqtbuild/builder.py", line 76, in apply_user_defaults self._get_qt_configuration() File "/tmp/pip-build-env-h65hqnoo/overlay/lib/python3.6/site-packages/pyqtbuild/builder.py", line 436, in _get_qt_configuration for line in project.read_command_pipe([self.qmake, '-query']): File "/tmp/pip-build-env-h65hqnoo/overlay/lib/python3.6/site-packages/sipbuild/project.py", line 374, in read_command_pipe "'{0}' failed returning {1}".format(cmd, pipe.returncode)) sipbuild.exceptions.UserException ---------------------------------------- ERROR: Command errored out with exit status 1: /usr/local/bin/python3.6 /usr/local/lib/python3.6/site-packages/pip/_vendor/pep517/_in_process.py prepare_metadata_for_build_wheel /tmp/tmplcfg2oqe Check the logs for full command output. ,而我尝试在函数主体中进行const int &x,则会收到编译时错误,该错误用于修改只读引用。但是,如果我像这样使用x++修饰符:

__restrict__

...我没有得到编译时错误。如果我未优化地运行此代码,则输出为void foo(int & __restrict__ a, int & __restrict__ b) { if (a == 1) b = 2; if (a == 2) b = 3; } int main() { int x = 1; foo(x, x); // should be illegal? cout << x; } ,但如果我以3或更高版本运行,则输出为-O1。似乎检测到2要通过两次很简单,并且很容易被禁止。为什么C ++可以防止对x的滥用,而不能对const的滥用呢?

3 个答案:

答案 0 :(得分:3)

在非常一般的情况下,不可能在编译时对其进行诊断。就像一个简单的反例一样,请考虑:

 void foo(int* __restrict__ a, int * __restrict__ b);

 int x;
 int y;
 std::cin >> x >> y;
 int* a = (x%2) ? &x : &y;
 int* b = (y%2) ? &x : &y;
 foo(a,b);

编译器无法知道ab是否指向相同的int。实际上,如果编译器可以进行这种分析,则不需要__restrict__限定符,因为这样编译器可以自己确定是否使用了两个指针来访问同一内存。

答案 1 :(得分:3)

您正在向后看__restrict__

__restrict__是一个实现扩展,程序员可以使用它来传达意图,以最大化生成的代码质量和性能(“优化”)。

这不是检查,也不是对程序的限制。

它不是类型系统的一部分,因此也不是函数类型的一部分,因此不能在调用站点上强制执行(通常)。

用来告诉编译器某些东西,就像其他一些扩展名(例如__builtin_unreachable)一样。

在这种情况下,您要告诉它“我不是在通过任何其他指针来指望指针”。

您并不是在问它“请阻止我通过任何其他指针来指代指针”。

C和C ++编译器已经在可能的地方执行了强大的“别名”检查。在自动混叠检测无法正常工作的情况下,__restrict__关键字可以让 you 告诉 it “我确定”。例如翻译单位边界)。由于自动别名检测无法正常工作,因此无法执行__restrict__

而且,即使可能,也与修饰符的目的相反。

答案 2 :(得分:2)

通常很难检测到restrict违规。假设您有一个功能

void bar(int* p1, int* p2) {
    foo(*p1, *p2);
}

在这种情况下,编译器应该做什么?

在某些情况下(例如您的示例),可以检测到restrict违例,并且某些编译器也可以检测到违规。例如,带有-Wrestrict的GCC会产生警告:

警告:将参数1传递给带有参数2的限定条件的参数别名

-Wrestrict上的

GCC documentation读取:

当由restrict限定的参数(或在C ++中,由__restrict限定的参数)引用的对象被另一个参数别名时,或当此类对象之间的副本重叠时,会发出警告。

您可以使用-Werror=restrict选项将此警告变成错误。