我写了一个 Object类,它有一个属性,希望它返回 typeid().name(),但当有中文变量时,
它输出的是乱码,花了五六小时,发现网上也有一位网友遇到同样的情况,他用的是Windows API ,下面是那位网友的贴子截图:
我代码出现问题的如下:
class Object
{
private:
/// <summary>
/// Object 对象计数器
/// </summary>
static __int64 _object_count;
protected:
inline virtual void InitData() {};
public://----------------------------------------------构造析构
Object();
~Object();
public:
inline virtual void ClearData() {};
public://----------------------------------------------------------------属性
inline static __int64 GetObjectCount() { return _object_count; }
__declspec(property(get = GetObjectCount)) __int64 ObjectCount;
inline const char* GetClassName() { return typeid(*this).name(); }
__declspec(property(get = GetClassName)) const char* ClassName;
};
如图:
输出:
但我不想用API,最后发现 typeid().name 是utf8格式的,只要找出API替代版本就行,幸苦
了很久,终于找到两种方法可以不用Windws API WideCharToMultiByte解决问题:
第一种,转换源码:
std::u32string UTF8ToUnicode(std::string const& utf8)
{
if (utf8.empty())
{
return {};
}
std::u32string res;
for (size_t i = 0; i < utf8.size(); )
{
auto c = (unsigned char)utf8[i];
char32_t wideChar = 0;
if ((c & 0x80) == 0)
{
wideChar = c;
++i;
}
else if ((c & 0xE0) == 0xC0) ///< 110x-xxxx 10xx-xxxx
{
if (i + 2 > utf8.size()) break;
wideChar = (char32_t(c) & 0x3F) << 6;
wideChar |= (char32_t(utf8[i + 1]) & 0x3F);
i += 2;
}
else if ((c & 0xF0) == 0xE0) ///< 1110-xxxx 10xx-xxxx 10xx-xxxx
{
if (i + 3 > utf8.size()) break;
wideChar = (char32_t(c) & 0x1F) << 12;
wideChar |= (char32_t(utf8[i + 1]) & 0x3F) << 6;
wideChar |= (char32_t(utf8[i + 2]) & 0x3F);
i += 3;
}
else if ((c & 0xF8) == 0xF0) ///< 1111-0xxx 10xx-xxxx 10xx-xxxx 10xx-xxxx
{
if (i + 4 > utf8.size()) break;
wideChar = (char32_t(c) & 0x0F) << 18;
wideChar |= (char32_t(utf8[i + 1]) & 0x3F) << 12;
wideChar |= (char32_t(utf8[i + 2]) & 0x3F) << 6;
wideChar |= (char32_t(utf8[i + 3]) & 0x3F);
i += 4;
}
else///< 1111-10xx 10xx-xxxx 10xx-xxxx 10xx-xxxx 10xx-xxxx
{
if (i + 4 > utf8.size()) break;
wideChar = (char32_t(c) & 0x07) << 24;
wideChar |= (char32_t(utf8[i + 1]) & 0x3F) << 18;
wideChar |= (char32_t(utf8[i + 2]) & 0x3F) << 12;
wideChar |= (char32_t(utf8[i + 3]) & 0x3F) << 6;
wideChar |= (char32_t(utf8[i + 4]) & 0x3F);
i += 4;
}
res.push_back(wideChar);
}
return res;
}
图(1)
第二种, 使用c++11标准库codecvt转换字符编码
const std::wstring utf8_2_ws(const std::string& src)
{
std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
return conv.from_bytes(src);
}
图(2)
当然我选择了第二种:
class Object
{
private:
/// <summary>
/// Object 对象计数器
/// </summary>
static __int64 _object_count;
protected:
inline virtual void InitData() {};
public://----------------------------------------------构造析构
Object();
~Object();
public:
inline virtual void ClearData() {};
public://----------------------------------------------------------------属性
inline static __int64 GetObjectCount() { return _object_count; }
__declspec(property(get = GetObjectCount)) __int64 ObjectCount;
inline const _string GetClassName()
{
#if UNICODE
std::wstring_convert<std::codecvt_utf8<wchar_t> > tmp;
return tmp.from_bytes(typeid(*this).name());
#else
return typeid(*this).name();
#endif
}
__declspec(property(get = GetClassName)) const _string ClassName;
};
修正:
当是多字节时,利用 wcstombs wchar_t* 字符再转化为 char *
#ifndef _LF_OBJ_H_
#define _LF_OBJ_H_
#include "macro.h"
_LF_BEGIN_
//#define _OBJECT_DEBUG_
//-----------------------------------------------------前置声明
//class Obj;
/// <summary>
/// 不命名 Obj ,是因为跟 System::Object 同名
/// </summary>
class Obj
{
private:
/// <summary>
/// Obj 对象计数器
/// </summary>
static __int64 _iObjectCount;
/// <summary>
/// 是否进行全局初始化
/// </summary>
static bool _bInitializeGlobal;
protected:
inline virtual void InitData();
public://----------------------------------------------构造析构
Obj();
virtual ~Obj();
public:
inline virtual void ClearData() {};
inline virtual _string ToString() { return _t(""); };
public: // 运算符重载
public:
public://----------------------------------------------------------------属性
inline static __int64 GetObjectCount() { return _iObjectCount; }
__declspec(property(get = GetObjectCount)) __int64 ObjectCount;
const _string GetTypeName();
/// <summary>
///
/// </summary>
__declspec(property(get = GetTypeName)) const _string ClassName;
};
const _string Obj::GetTypeName()
{
wstring wText = str.s_UTF8String_to_TextW(typeid(*this).name());
#ifdef _UNICODE_
return wText;
#else
return str.s_wstring_to_string(wText);
#endif
}
string Framework_branch_str::s_wstring_to_string(const wstring& w)
{
Mem<char> m(w.length() * 2 + 1);
wcstombs_s((size_t*)&m.effectiveCount, m.data, w.length() * 2, w.c_str(),w.length() * 2);
return m.data;
}