yep*_*ons 38 c++ gcc posix language-lawyer clang++
考虑以下 C++17 代码:
#include <iostream>
int read;
int main(){
std::ios_base::sync_with_stdio(false);
std::cin >> read;
}
Run Code Online (Sandbox Code Playgroud)
它可以在使用 GCC 11.2 和 Clang 12.0.1 的Godbolt上编译并正常运行,但如果使用密钥编译,则会导致运行时错误-static。
据我了解,有一个名为 POSIX(?) 的函数read(请参阅man read(2)),因此上面的示例实际上会调用 ODR 违规,并且即使在没有-static. 如果我尝试命名变量,GCC 甚至会发出警告malloc:built-in function 'malloc' declared as non-function
上面的程序是有效的 C++17 吗?如果没有,为什么?如果是,是否是编译器错误导致其无法运行?
asc*_*ler 17
显示的代码是有效的(我相信所有 C++ 标准版本)。类似的限制都列在[reserved.names]中。由于read未在 C++ 标准库、C 标准库或旧版本的标准库中声明,并且没有以其他方式列出,因此它作为全局命名空间中的名称是公平的。
那么它是否是一个无法链接的实现缺陷-static?(不是“编译器错误” - 工具链的编译器部分很好,并且没有什么禁止对有效代码发出警告。)它至少可以使用默认设置(尽管因为 GNU 链接器不介意重复的符号)在动态库的未使用的对象中),有人可能会说这就是标准合规性所需的全部。
一致的实现可以具有扩展(包括附加的库函数),只要它们不改变任何格式良好的程序的行为。根据本国际标准,需要实施来诊断使用此类格式错误的扩展的程序。然而,这样做之后,他们可以编译并执行此类程序。
我们可以将 POSIX 函数视为这样的扩展。对于何时或如何启用此类扩展,故意含糊其辞。GCC工具集的g++驱动程序默认链接了许多库,我们可以认为这不仅增加了非标准#include头文件的可用性,而且还为程序添加了额外的翻译单元。理论上,g++ 驱动程序的不同参数可能使其在没有使用 的底层链接步骤的情况下工作libc.so。但祝你好运 - 有人可能会说,没有简单的方法可以仅链接 C++ 和 C 标准库中的名称而不包含其他未保留的名称,这是一个问题。
(不改变格式良好的程序甚至意味着实现扩展不能使用附加库的非保留名称吗?我希望不会,但我可以看到严格的阅读暗示了这一点。)
因此,我没有对这个问题提出明确的答案,但实际情况不太可能改变,而且在我看来,标准缺陷报告比有用的澄清更挑剔。
这里有一些关于为什么它只产生运行时错误的解释-static。
问题中的https://godbolt.org/z/asKsv95G5链接表明运行时错误-static是Program returned: 139。kill -lLinux 上 Bash的输出包含11) SIGSEGV(and 128 + 11 = 139),因此进程退出时会出现致命信号 SIGSEGV(分段错误),指示 无效的内存引用。原因是该进程尝试将读取变量的内容(4 个字节)作为机器代码运行。(最终std::cin >> ...调用read。)要么这 4 个字节中的某些内容意外解释为机器代码而失败,要么因为包含这 4 个字节的内存页不可执行而失败。
它成功的原因-static是,通过动态链接,可以有多个具有相同名称的符号(read):一个在程序可执行文件中,另一个在共享库中(libc.so.6)。std::cin >> ...(在libstdc++.so.6中)链接到libc.so.6 ,因此当动态链接器尝试查找在程序加载时读取的符号(由libstdc++.so.6使用)时,它将查看libc.so .6首先,找到read,并忽略程序可执行文件中的read符号。
| 归档时间: |
|
| 查看次数: |
3200 次 |
| 最近记录: |