提问人:yeputons 提问时间:10/3/2021 最后编辑:yeputons 更新时间:10/4/2021 访问量:3186
是否允许在 C++ 中将全局变量命名为“read”或“malloc”?
Is it allowed to name a global variable `read` or `malloc` in C++?
问:
请考虑以下 C++ 17 代码:
#include <iostream>
int read;
int main(){
std::ios_base::sync_with_stdio(false);
std::cin >> read;
}
它可以在 GCC 11.2 和 Clang 12.0.1 的 Godbolt 上编译并运行良好,但如果使用密钥编译,则会导致运行时错误。-static
据我了解,有一个 POSIX(?) 函数叫做(参见 man read(2)
),所以上面的例子实际上调用了 ODR 冲突,即使编译时没有 .如果我尝试命名一个变量,GCC 甚至会发出警告:read
-static
malloc
built-in function 'malloc' declared as non-function
上面的程序是否有效 C++17?如果不是,为什么?如果是,是编译器错误阻止了它运行吗?
答:
显示的代码是有效的(我相信所有 C++ 标准版本)。类似的限制都列在 [reserved.names] 中。由于未在 C++ 标准库、C 标准库、旧版本的标准库中声明,并且未在此处列出,因此在全局命名空间中作为名称是公平的。read
那么,这是一个不会与之相关的实现缺陷吗?(不是“编译器错误”——工具链的编译器部分很好,没有什么禁止对有效代码发出警告。它至少可以在默认设置下工作(尽管因为 GNU 链接器不介意动态库中未使用的对象中的重复符号),有人可能会争辩说这就是标准合规性所需要的。-static
我们也有 [intro.compliance]/8
符合要求的实现可以具有扩展(包括附加库函数),前提是它们不会改变任何格式良好的程序的行为。根据本国际标准,需要实现来诊断使用格式错误的此类扩展的程序。但是,这样做后,他们可以编译和执行此类程序。
我们可以将 POSIX 函数视为这样的扩展。对于何时或如何启用此类扩展,这是故意含糊其辞的。默认情况下,GCC 工具集的 g++ 驱动程序链接了许多库,我们可以认为这不仅增加了非标准标头的可用性,而且还为程序添加了额外的翻译单元。从理论上讲,对 g++ 驱动程序的不同参数可能会使其在没有基础链接步骤的情况下工作。但祝你好运 - 有人可能会争辩说,没有简单的方法可以仅链接 C++ 和 C 标准库中的名称而不包含其他未保留的名称,这是一个问题。#include
libc.so
(不更改格式正确的程序是否意味着实现扩展不能对其他库使用非保留名称?我希望不是,但我可以看到一个严格的解读暗示了这一点。
因此,我还没有对这个问题提出明确的答案,但实际情况不太可能改变,在我看来,标准缺陷报告更像是吹毛求疵,而不是有用的澄清。
评论
read
fread
malloc
malloc
-fno-builtin-malloc
__builtin_malloc
-fno-builtin
Here is some explanation on why it produces a runtime error with only.-static
The https://godbolt.org/z/asKsv95G5 link in the question indicates that the runtime error with is . The output of in Bash on Linux contains (and 128 + 11 = 139), so the process exits with fatal signal SIGSEGV (Segmentation fault) indicating invalid memory reference. The reason for that is that the process tries to run the contents (4 bytes) of the read variable as machine code. (Eventually calls read.) Either somethings fails in those 4 bytes accidentally interpreted as machine code, or it fails because the memory page containing those 4 bytes is not executable.-static
Program returned: 139
kill -l
11) SIGSEGV
std::cin >> ...
The reason why it succeeds without is that with dynamic linking it's possible to have multiple symbols with the same name (read): one in the program executable, and another one in the shared library (libc.so.6). (in libstdc++.so.6) links against libc.so.6, so when the dynamic linker tries to find the symbol read at program load time (to be used by libstdc++.so.6), it will look at libc.so.6 first, finding read there, and ignoring the read symbol in the program executable.-static
std::cin >> ...
评论
sync_with_stdio(0)
<iostream>