导入命名空间并导入全局命名空间的C函数之间的冲突

时间:2012-08-01 07:34:53

标签: c++ namespaces

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

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

但我刚刚发现,如果我在使用具有OpenSSL支持的Boost ASIO时尝试这样做,这似乎会导致爆炸,但似乎将OpenSSL符号带入全局命名空间。有什么我可以做的,或者我只需要将所有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。 “

2 个答案:

答案 0 :(得分:3)

一般情况下,这不起作用,也不应该这样。 Boost.Asio可以(并且应该)期望能够将OpenSSL类型引用为全局命名空间,例如引用::buf_mem_st,但由于您已将其声明为OpenSSL::buf_mem_st而失败。

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

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

说不。

答案 1 :(得分:0)

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

因此,如果你要在你的编译单元中使用Boost.ASIO,这需要它们在全局命名空间中,你要么自己将它们带入全局命名空间(在你之前) > #include&lt; boost / asio.hpp&gt; 或让 #include&lt; boost / asio.hpp&gt; 这样做。