2014-09-11 49 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功能簽名)。