【问题标题】:Clash between C functions imported into a namespace and imported into the global namespace导入命名空间和导入全局命名空间的 C 函数之间的冲突
【发布时间】:2012-08-01 07:34:53
【问题描述】:

在我的代码中,我将 OpenSSL 标头放入命名空间中,如下所示:

#include <cstdio>
namespace OpenSSL {
    #include <openssl/ssl.h>
    #include <openssl/err.h>
}

但我刚刚发现,如果我在使用具有 OpenSSL 支持但似乎将 OpenSSL 符号带入全局命名空间的 Boost ASIO 时尝试这样做,这似乎会导致事情爆炸。对此我能做些什么吗,还是我只需将 OpenSSL 库的所有符号留在全局命名空间中?

我只是想在包含我的标头后在有问题的文件中尝试“使用命名空间 OpenSSL”,但不幸的是,这会导致错误,例如:

/usr/include/openssl/x509v3.h:83:13: error: reference to ‘v3_ext_ctx’ is ambiguous
/usr/include/openssl/x509v3.h:71:8: error: candidates are: struct v3_ext_ctx
/usr/include/openssl/ossl_typ.h:160:16: error:                 struct OpenSSL::v3_ext_ctx

(请注意,OpenSSL 是一个 C 库,而不是 C++ 库,因此原始函数在引入 C++ 编译单元之前不在任何命名空间中。Stroustrup 在他的书The C++ 中推荐了我的技术编程语言,特别版。来自第 9.5 节,“建议”:“[8] #include 命名空间中的 C 标头以避免全局名称;§8.2.9.1,§9.2.2。 "

【问题讨论】:

  • 您能详细说明一下那些“爆炸物”吗?我能够创建的一个非常短的示例似乎编译得很好,但也许我遗漏了一些东西。
  • 如果在 C++ 文件中包含上述文件,后跟“#include ”,您会看到问题。产生的错误信息很多,具体的设置取决于上面的头文件是包含在asio之前还是之后。如果您在重现问题时遇到问题,请随时直接给我发电子邮件(我的地址在我的用户页面上)。
  • 我假设你的意思是 8.2.9(没有 8.9.2)但它没有这么说。

标签: c++ namespaces


【解决方案1】:

一般来说这是行不通的,也不应该这样做。 Boost.Asio 可以(并且应该)期望能够将 OpenSSL 类型引用为在全局命名空间中,例如通过引用::buf_mem_st,但由于您导致将其声明为OpenSSL::buf_mem_st,因此失败了。

另外,如果&lt;openssl/ssl.h&gt; 包含另一个标题,比如&lt;stddef.h&gt;(它确实如此),然后将size_t 定义为OpenSSL::size_t,会发生什么情况。任何包含&lt;stddef.h&gt; 的后续代码都不会再次包含它,因为它包含保护宏,现在您的程序永远不能使用::size_t,因为它被错误地声明为OpenSSL::size_t - 对于许多实现,这将破坏大部分C++ 标准如果在您的 openssl 包含之后包含库。在您的情况下,&lt;cstdio&gt; 可能无论如何都包含&lt;stddef.h&gt;,但这同样适用于 OpenSSL 标头包含的任何标准(即非 OpenSSL)标头,例如 &lt;sys/types.h&gt;。您的程序定义了OpenSSL::pid_tOpenSSL::off_tOpenSSL::timeval 等。

解决该问题的唯一方法是在执行 include-in-a-namespace 之前包含 每个 标准 C 标头,这样如果 OpenSSL 尝试再次包含该标头,它就会已正确包含在全局命名空间中。即使这样,其他引用 OpenSSL 的标头(例如 Boost.Asio)也可能会中断。

说不。

【讨论】:

  • Re,“另外,如果 包含另一个标题会发生什么...”:这就是我 #include 的原因。 ...等等,我突然想到,对于 stddef.h 等,我可能需要相当于 #include 的东西。嗯。感谢您的洞察力。
  • 是的,openssl 库可能包含的 每个 标头都需要它(现在或任何将来的版本!)
  • 我觉得你有点反应过度了。 只要应该不会有太多问题,因为所有头文件都正确引用了它们的依赖关系,并且“命名空间 C 包含”在最后。当然,这仅在没有其他 C++ 包含引用 OpenSSL 的情况下才有效。正如 boost.asio 所做的那样,即使尝试命名它也没有意义,因为它无论如何都会触及全局命名空间。
  • @MichałGórny,只有在没有其他 C++ 包含引用 OpenSSL 时才有效,这正是 OP 的问题你基本上重复了我所说的:在openssl 的,如果有其他东西引用 openssl 则它将不起作用
【解决方案2】:

所以问题似乎是这样的:OpenSSL 的符号只能引入一次;由于包含保护,第二个 #include 将不起作用。这意味着它们只能被引入一个编译单元中的一个命名空间。

因此,如果您要在编译单元中使用 Boost.ASIO,这要求它们位于全局命名空间中,您必须自己将它们引入全局命名空间(在您 #include 或让 #include 这样做。

【讨论】:

    猜你喜欢
    • 2011-04-21
    • 1970-01-01
    • 2014-12-02
    • 1970-01-01
    • 2012-01-11
    • 1970-01-01
    • 2022-01-06
    • 2013-04-12
    • 1970-01-01
    相关资源
    最近更新 更多