xsk*_*xzr 5 c++ one-definition-rule c++-standard-library language-lawyer c-standard-library
#include <cmath>
double log(double) {return 1.0;}
int main() {
log(1.0);
}
Run Code Online (Sandbox Code Playgroud)
假设函数log()in<cmath>是在全局命名空间中声明的(这实际上是未指定的,我们只是假设),那么它引用的函数与log()我们定义的函数相同。
那么这段代码是否违反了一个定义规则(参见这里,因为不需要诊断,这段代码可能会在某些编译器中编译,我们无法断言它是否正确)?
注意:经过最近的编辑,这不是以下内容的重复:C++ 中的一个定义规则究竟是什么?
如果extern "C" double log(double)最初是在全局命名空间中声明的,那么您已重新声明它并提供了定义。实现之前提到的extern "C"会延续到您的匹配重新声明中。您的定义适用于属于实现的函数,这是 ODR 违规。
log至于UB的表现形式:显然,将其视为弱链接符号是很常见的。您的实现会libc.so根据 ABI 规则进行覆盖。
(如果实现不这样做extern "C",它仍然基本上是一样的。)
如果在全局命名空间log中声明namespace std然后带入全局命名空间,那么您的声明将与其冲突。(实际上,using声明在技术上就是声明。)诊断出此错误。
\n\n\n\n
log那么它指的是与我们定义的函数相同的函数
实现将<cmath>名称放入全局命名空间的一种方法是在extern "C"内部声明函数namespace std,然后执行 do using namespace std,并确保在包含任何标准标头时始终将这作为第一件事发生。由于using namespace\xe2\x80\x94 不是“粘性”的,因此它仅适用于指定命名空间 \xe2\x80\x94 中的前面的声明,因此标准库的其余部分将不可见。(这不会在全局命名空间中声明名称,但标准只说“放置在全局命名空间范围内。”)
在这样的实现中,您的声明将隐藏标准函数并声明一个具有新的损坏名称(而_Z3logd不是简单的log)和新的完全限定名称(::log而不是::std::log)的新函数。这样就不会有 ODR 违规(除非某些内联函数log在一个 TU 中使用一个函数,而在另一个 TU 中使用另一个函数)。
| 归档时间: |
|
| 查看次数: |
1293 次 |
| 最近记录: |