我正在重新研究一个旧的MFC业余项目,并试图使其对Unicode更友好。因此,我一直将char
的所有实例替换为TCHAR
,将strlen()
替换为_tcslen()
,依此类推。
但是,I just discovered实际上这些类型和功能与所有语言字符集不兼容。例如,日语字符显然由三个字节而不是一个字节表示:
我想知道TCHAR数组或TCHAR *中的字符数。不幸的是,我可以找到的每个长度函数(_tcslen(),甚至wstring :: length())似乎都返回了BYTES的数量,而不是字符...日语字符算作3,而罗马字符算作1。 / p>
但是,this Microsoft documentation page建议使用TCHAR
可以在所有情况下确保您的安全:
为了在所有情况下都安全,在处理TCHAR时应使用以下约定:
TCHAR tchBuffer[24]; GetWindowText( hWnd, tchBuffer, sizeof(tchBuffer)/sizeof(TCHAR));
这样做,将您的代码编译为MBCS或UNICODE时将是安全的。
这是真的吗?还是将诸如日文这样的多字节字符集生成为UB? MTIA:-)
答案 0 :(得分:2)
您确实需要确定主要的api是您的应用程序目标。
如果已将其标记为基于MFC的,则应使用MFC的c ++字符串表示形式CString及其在Windows平台上处理Ansi和Unicode的规则。
同样,如果您主要是针对Windows API编写的,则定义的类型为:CHAR,TCHAR和WCHAR用于字符文字,而* STR,* TSTR和* WSTR用于字符串缓冲区。
如果您是首先编写一个c ++应用程序-碰巧是在Windows上实现的-那么则更喜欢std:类型,例如std:string和std:wstring
最后,如果要通过字符串的C表示形式表示字符串,则可以使用char *,wchar_t *表示,如果希望能够在unicode和ansi之间动态切换,则可以使用_tchar *及其在.in中定义的帮助程序类型。 / p>
在Ansi和Uniocode之间切换 在所有类型中,当在Ansi和Unicode之间切换编译器时,CString,TCHAR,* TSTR和_tchar将在8位和16位类型之间切换。
但实际上-将应用程序编译为Ansi: *由于Windows API一直是nativley unicode已有一段时间了,因此效率低下,因此Ansi应用程序中所有具有字符串参数的api调用都必须在进出时将所有in参数转换为出入参数。 *易于丢失数据,因为Ansi应用程序永远(几乎)永远无法同时使用来自两个不同代码页的字符。
Ansi / MBCS可以安全地编码什么
Windows API定义了“ Ansi代码页”。我不知道为什么叫Ansi,但是您可以通过调用GetACP
来获得当前的Ansi。如果将其设置为例如CP_LATIN1,然后尝试加载,处理,输入或处理日语,韩语等字符将失败。这是区域设置控制面板中的系统范围默认设置,因此通常您应该为本地用户使用正确的代码页。
如果您正在使用c运行时函数,则需要调用setlocale
以确保 it 知道您正在使用哪种编码。我不确定std :: string是否使用c语言环境,或者是否存在此想法的std ::抽象。关键是,要知道您主要使用的是哪种字符串抽象,并使用它,因此您不必仅对某些不同的本地或代码页面api进行调用就可以对代码进行修饰再次弹出一个字符串。
上手:Utf8 另一方面,其他行业则朝着另一个方向发展,Linux,MacO和相应的大多数跨平台库使用Utf8编码处理unicode字符。可以对所有可能的unicode字符进行编码,而不会与语言环境或代码页或任何废话混为一谈。以及所有具有跨平台友好性的“ char *”。 因此,如果编写跨平台代码对您很重要,那么您将不会使用wchar_t或任何宽字符类型。 Windows 10最终将Utf8添加为可能的Ansi代码页BUT:这是用户必须选择加入的系统设置,因此您的应用程序无法声明或依赖于启用它。我不知道是否可以简单地将其设置为当前线程代码页,我也不知道是否有任何c运行时兼容/利用此优势提供无缝的“更接近posix”体验您可以期望字符串可以正常工作。
当然,这里需要说明的是,“字符”现在可以被编码为1到6个字节长。
字节长度与字符数 不确定在这里想要什么。通常,您不希望* strlen之类的函数返回字符数,因为(通常)要使用它们的结果来分配内存缓冲区。但是,它们应该返回的计数不是以字节为单位,而是以您要处理的字符的自然分配单位为单位。即wcslen(“ hello”)应该返回5,而不管wchar_t的宽度如何,该宽度可以为2或4个字节。
wchar_t wchar_t是一种可怕的类型,因为c / c ++标准未定义其宽度。一些编译器以2字节为单位,其他为4字节。作为2字节单元,它仅足够宽以存储来自Unicode“ BMP”或基本多语言平面的字符,但是有些字符不能存储为单个UCS2 / UTF-16字符。如果要100%安全,则必须使用char16_t,char32_t或您特别需要的任何东西。 wchar_t不是安全的选项。
总的说来,这是完全可恨的:
答案 1 :(得分:0)
如评论中所述,使用wchar_t会产生更好的结果。
MFC是在通常使用char的时候设计的,而多字节字符集只能编码一种语言(例如Shift-JIS是日语字符的编码)。
从那时起,wchar_t已被用作可用集(在Windows上,wchar_t是无符号的缩写,并且编码UTF-16)。
我的建议是直接转换为wchar_t,而忽略tchar中间位置。
UTF-16确实对一些具有多个int16值的字符进行了编码
答案 2 :(得分:0)
这样做,将您的代码编译为MBCS或UNICODE时将是安全的。
这是不正确的,无论您使用的是哪种基本字符类型。
以任意/缓冲区大小的偏移量剪切未知字符串永远都不安全。 UTF-16(在Windows平台上为wchar_t
)具有guide,即使您切换到UTF-32,您仍然会遇到surrogate pairs,decomposed combining characters和颜色修饰符的问题。 / p>
使用GetStringType
获取有关特定字符的信息和/或使用CharNext
遍历字符串以找到某个合适的停止点。