2014-09-11 54 views
1

我正在移植使用Xerces-c进行从Windows/VC++到Linux/G ++的XML处理的代码库。Xerces-c和跨平台字符串文字

在Windows上,Xerces-c使用wchar_t作为字符类型XmlCh。这使得人们可以使用std::wstringL""语法的字符串文字。

在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代码。

回答

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(“string”)。每当您从Xerces获取一个字符串时,都会将其转换为u16string_t(US(call_xerces_function()))

请注意,也可以使用设置为char16_t的字符类型重新编译Xerces-C。这消除了上面所需的大量工作。 但是您将无法在系统上使用任何其他库,而这些库又取决于Xerces-C。链接到任何这样的库将导致链接错误(因为更改字符类型会更改许多Xerces功能签名)。