4

在我的代码中,我将 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 在他的《C++ 编程语言,特别版》一书中推荐了我的技术。来自第 9.5 节,“建议”:“[8] #include C headers in namespaces to avoid global names;§8.2.9.1, §9.2.2。”

4

2 回答 2

3

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

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

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

拒绝吧。

于 2012-08-01T08:04:38.077 回答
0

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

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

于 2012-08-02T02:51:40.590 回答