从标准库中重新定义函数是否违反一定义规则? [英] Does redefining a function from the standard library violate the one-definition rule?

查看:274
本文介绍了从标准库中重新定义函数是否违反一定义规则?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

#include <cmath>

double log(double) {return 1.0;}
int main() {
  log(1.0);
}

假设<cmath>中的函数log()是在全局命名空间中声明的(实际上这是未指定的,我们只是作此假设),然后它所引用的函数与我们定义的log()函数相同. br> 因此,此代码是否违反了一个定义规则(请参见此处,由于不需要诊断,因此该代码可以在某些编译器中编译,我们无法断言它是否正确)?

Suppose the function log() in <cmath> is declared in global namespace (this is unspecified in fact, and we just make this assumption), then it refers to the same function as the log() function we defined.
So does this code violate the one-definition rule (see here, since no diagnostic required, this code may compile in some compiler and we cannot assert if it is correct)?

注意:最近的修改后,这不是以下内容的重复:确切的定义规则是什么C ++?

Note: After recent edits, this is not a duplicate of: What exactly is One Definition Rule in C++?

推荐答案

典型方案.

如果extern "C" double log(double)最初是在全局名称空间中声明的,则您已重新声明它并提供了定义.该实现先前提到的extern "C"会延续到您的匹配重新声明中.您的定义适用于属于实现的函数,并且违反了ODR.

Typical scenario.

If extern "C" double log(double) is initially declared in the global namespace, then you have redeclared it and provided a definition. The implementation's previous mention of extern "C" carries over to your matching redeclaration. Your definition applies to the function belonging to the implementation, and it is an ODR violation.

至于UB的表现:将log视为弱连接子符号似乎很常见.根据ABI规则,您的实现会覆盖libc.so.

As for the manifestation of UB: It's apparently common to treat log as a weak linker symbol. Your implementation overrides libc.so according to ABI rules.

(如果实现不执行extern "C",则基本上还是一样.)

(If the implementation doesn't do extern "C", it's still basically all the same.)

如果lognamespace std中声明,然后带入全局名称空间,则您的声明将与其冲突. (实际上,using声明实际上是一个声明.)此错误被诊断.

If log is declared in namespace std and then brought into the global namespace, then your declaration will conflict with it. (Actually, a using declaration is technically a declaration.) This error is diagnosed.

然后它指的是与我们定义的log函数相同的函数

实现将<cmath>名称放入全局命名空间的一种方法是在namespace std内声明extern "C"函数,然后执行using namespace std,并确保在任何情况下都始终将其作为第一件事包含标准标头.由于using namespace不是粘性"的-它仅适用于指定命名空间中的先前声明-标准库的其余部分将不可见. (这不会声明全局名称空间中的名称,但是标准仅说放置在全局名称空间范围内".)

One way for the implementation to put <cmath> names into the global namespace would be to declare extern "C" functions inside namespace std, then do using namespace std, and to ensure that this always happens as the first thing when any standard header is included. Since using namespace isn't "sticky" — it only applies to preceding declarations in the nominated namespace — the rest of the standard library would not be made visible. (This would not declare the names in the global namespace, but the standard only says "placed within the global namespace scope.")

在这样的实现中,您的声明将隐藏标准的声明,并声明具有新名称(例如,用_Z3logd而不是简单地log)和新的完全限定名称(::log来代替)的新函数. ::std::log).这样就不会违反ODR(除非某个内联函数在一个TU中使用一个log在另一个TU中使用另一个log).

In such an implementation, your declaration would hide the standard one and declare a new function with a new mangled name (say _Z3logd instead of simply log) and a new fully-qualified name (::log instead of ::std::log). Then there would be no ODR violation (unless some inline function uses one log in one TU and the other in a different TU).

这篇关于从标准库中重新定义函数是否违反一定义规则?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆