2014-09-11 9 views
1

Windows/VC++에서 Linux/G ++ 로의 XML 처리를 위해 Xerces-c를 사용하는 코드 기반을 이식하고 있습니다.Xerces-c 및 플랫폼 간 문자열 리터럴

Windows에서 Xerces-c는 XmlCh 문자 유형으로 wchar_t을 사용합니다. 이로 인해 사람들은 std::wstringL"" 구문의 문자열 리터럴을 사용할 수 있습니다.

Linux/G ++의 경우 wchar_t은 32 비트이고 Xerces-c는 XmlCh 문자로 unsigned short int (16 비트)을 사용합니다.

나는이 트랙을 따라 시작했습니다

#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은 동일하지 않으며 자신의 포인터를 암시 적으로 변환되지 않습니다. 따라서 Xerces 함수에 u"Hello, world."을 전달해도 잘못된 변환 오류가 발생합니다.

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()))으로 다시 변환하십시오.

Xerces-C를 char16_t로 설정된 문자 유형으로 다시 컴파일 할 수도 있습니다. 이것은 위에서 요구되는 많은 노력을 제거합니다. BUT 시스템에서는 Xerces-C에 의존하는 다른 라이브러리를 사용할 수 없습니다. 이러한 라이브러리에 링크하면 링크 오류가 발생합니다 (문자 유형을 변경하면 많은 Xerces 함수 서명이 변경되기 때문에).