-->

的Xerces-C和跨平台的字符串文字(Xerces-c and cross-platform st

2019-10-20 22:46发布

我移植使用的Xerces-C用于XML处理从Windows / VC ++到Linux / G ++一个代码库。

在Windows中,的Xerces-C使用wchar_t的字符类型XmlCh 。 这使得人们使用std::wstring和字符串文字L""语法。

在Linux / G ++, wchar_t是32位和Xerces-C使用unsigned short int (16位)作为字符类型XmlCh

我沿着这条赛道开始了:

#ifdef _MSC_VER
using u16char_t = wchar_t;
using u16string_t = std::wstring;
#elif defined __linux
using u16char_t = char16_t;
using u16string_t = std::u16string;
#endif

不幸的是, char16_tunsigned short int是不等价的和他们的指针不是隐式转换。 因此,通过u"Hello, world." 到Xerces的功能仍然会导致无效的转换错误。

它开始看起来像我将不得不显式强制每个字符串我传递给Xerces的功能。 但我做之前,我想问如果有谁知道一个更理智的方式来编写跨平台的Xerces-C代码。

Answer 1:

答案是否定的,没有人对如何做到这一点是一个好主意。 对于其他人谁发现这个问题,这是我想出了:

#ifdef _MSC_VER
#define U16S(x) L##x
#define U16XS(x) L##x

#define XS(x) x
#define US(x) x

#elif defined __linux

#define U16S(x) u##x
#define U16XS(x) reinterpret_cast<const unsigned short *>(u##x)

inline unsigned short *XS(char16_t* x) {
    return reinterpret_cast<unsigned short *>(x);
}
inline const unsigned short *XS(const char16_t* x) {
    return reinterpret_cast<const unsigned short *>(x);
}
inline char16_t* US(unsigned short *x) {
    return reinterpret_cast<char16_t *>(x);
}
inline const char16_t* US(const unsigned short *x) {
    return reinterpret_cast<const char16_t*>(x);
}

#include "char16_t_facets.hpp"
#endif

namespace SafeStrings {
#if defined _MSC_VER

    using u16char_t = wchar_t;
    using u16string_t = std::wstring;
    using u16sstream_t = std::wstringstream;
    using u16ostream_t = std::wostream;
    using u16istream_t = std::wistream;
    using u16ofstream_t = std::wofstream;
    using u16ifstream_t = std::wifstream;
    using filename_t = std::wstring;

#elif defined __linux

    using u16char_t = char16_t;
    using u16string_t = std::basic_string<char16_t>;
    using u16sstream_t = std::basic_stringstream<char16_t>;
    using u16ostream_t = std::basic_ostream<char16_t>;
    using u16istream_t = std::basic_istream<char16_t>;
    using u16ofstream_t = std::basic_ofstream<char16_t>;
    using u16ifstream_t = std::basic_ifstream<char16_t>;
    using filename_t = std::string;

#endif

char16_t_facets.hpp具有模板特的定义std::ctype<char16_t> std::numpunct<char16_t> std::codecvt<char16_t, char, std::mbstate_t> 因此有必要将这些添加到全局区域,伴随着std::num_get<char16_t>std::num_put<char16_t>但没有必要为这些提供专业化)。 对于代码codecvt是很困难的唯一位,以及合理的模板可以在GCC 5.0库中找到(如果你使用GCC 5,你并不需要提供codecvt专业化因为它已经在图书馆)。

一旦你完成了所有这一切,对char16_t流将正常工作。

然后,每次你定义一个宽字符串,而不是L"string" ,写U16S("string") 每一次你通过一个字符串Xerces的时间,写XS(string.c_str())或U16XS(“串”)的文字。 每次你从Xerces的得到一个字符串返回时,将其转换回为u16string_t(US(call_xerces_function()))

请注意,它也有可能的Xerces-C编译设定为char16_t字符类型。 这消除了许多上述所需的工作。 你将无法使用任何其他库又依赖于的Xerces-C系统。 链接到任何这样的库将导致链接错误(因为改变字符类型改变很多了Xerces函数签名)。



文章来源: Xerces-c and cross-platform string literals