我对unsigned char
(在WinAPI中也是BYTE
)和char
指针之间的差异感到有些困惑。
目前我正在处理一些基于ATL的遗留代码,我看到了很多类似的表达式:
CAtlArray<BYTE> rawContent;
CALL_THE_FUNCTION_WHICH_FILLS_RAW_CONTENT(rawContent);
return ArrayToUnicodeString(rawContent);
// or return ArrayToAnsiString(rawContent);
现在,ArrayToXXString
的实现看起来如下:
CStringA ArrayToAnsiString(const CAtlArray<BYTE>& array)
{
CAtlArray<BYTE> copiedArray;
copiedArray.Copy(array);
copiedArray.Add('\0');
// Casting from BYTE* -> LPCSTR (const char*).
return CStringA((LPCSTR)copiedArray.GetData());
}
CStringW ArrayToUnicodeString(const CAtlArray<BYTE>& array)
{
CAtlArray<BYTE> copiedArray;
copiedArray.Copy(array);
copiedArray.Add('\0');
copiedArray.Add('\0');
// Same here.
return CStringW((LPCWSTR)copiedArray.GetData());
}
所以,问题:
从BYTE*
到LPCSTR
(const char*
)的C风格演员是否对所有可能的案件都安全?
将数组数据转换为宽字符串时,是否真的有必要添加 double 空终止?
转化例程CStringW((LPCWSTR)copiedArray.GetData())
对我来说似乎无效,是真的吗?
如何让所有这些代码更易于理解和维护?
答案 0 :(得分:3)
对于字节的定义,C标准有点奇怪。你确实有几个保证。
这个定义与字节长度为6或7位的旧平台不能很好地融合,但它确实意味着BYTE*,
和char *
保证是等价的。
Unicode字符串末尾需要多个空值,因为有一些有效的Unicode字符以零(空)字节开头。
至于使代码更容易阅读,这完全是一种风格问题。此代码似乎是以许多旧的C Windows代码使用的样式编写的,这些代码肯定不受欢迎。可能有很多方法可以让你更清楚,但如何让它更清晰没有明确的答案。
答案 1 :(得分:2)
是的,它总是安全的。因为它们都指向一个单字节内存位置数组
LPCSTR
:指向Const的长指针(单字节)字符串
LPCWSTR
:指向宽范围(多字节)字符串的长指针
LPCTSTR
:指向Const上下文的长指针(单字节或多字节)字符串
在宽字符串中,每个字符占用2个字节的内存,包含字符串的内存位置长度必须是2的倍数。因此,如果要添加宽'\ 0'到在字符串的结尾处,您应该添加两个字节。
对不起这部分,我不知道ATL,我在这方面无法帮助你,但实际上我认为这里没有复杂性,而且我觉得它很容易维护。您真正希望使用哪些代码更容易理解和维护?
答案 2 :(得分:1)
CString
是微软对用户友好字符串的最佳尝试。例如,无论CString本身是否宽泛,其构造函数都可以处理char
和wchar_t
类型的输入,因此您不必担心转换太多。编辑:等等,现在我看到他们正在滥用BYTE数组来存储宽字符。我不能推荐。
答案 3 :(得分:0)
LPCWSTR是一个字符串,每个字符有2个字节,“char”是每个字符一个字节。这意味着你不能用C风格转换它,因为你必须调整内存(在每个标准ASCII之前添加一个“0”),而不只是以与内存不同的方式读取数据(什么是C-Cast)会做)。 因此演员阵容不那么安全。
Double-Nulltermination:您总是将2个字节作为一个字符,因此您的“字符串结束”符号必须为2个字节长。
为了使代码更易于理解,请参阅Boost中的lexical_cast(http://www.boost.org/doc/libs/1_48_0/doc/html/boost_lexical_cast.html)
另一种方法是使用std :: strings(使用类似std :: basic_string;),你可以执行String操作。