5

我对unsigned char(也在BYTEWinAPI 中)和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( )的 C 风格转换是否安全?const char*

  • 将数组数据转换为宽字符串时是否真的需要添加双空终止?

  • 转换例程CStringW((LPCWSTR)copiedArray.GetData())对我来说似乎无效,是真的吗?

  • 有什么方法可以让所有这些代码更容易理解和维护?

4

4 回答 4

3

当涉及到字节的定义时,C 标准有点奇怪。不过,您确实有几个保证。

  • 一个字节的大小总是一个字符
    • sizeof(char) 总是返回 1
  • 一个字节的大小至少为 8 位

此定义与字节长度为 6 或 7 位的旧平台不太吻合,但它确实意味着BYTE*,并且char *保证是等效的。

Unicode 字符串末尾需要多个空值,因为存在以零(空)字节开头的有效 Unicode 字符。

至于使代码更易于阅读,那完全是风格问题。这段代码似乎是用许多旧的 C Windows 代码所使用的风格编写的,这种风格肯定已经失宠了。可能有很多方法可以让你更清楚,但如何让它更清楚却没有明确的答案。

于 2012-02-10T14:09:47.210 回答
2
  • 是的,它总是安全的。因为它们都指向一个单字节内存位置数组。
    LPCSTR: Long Pointer to Const (single-byte) String
    LPCWSTR: Long Pointer to Const Wide (multi-byte) String
    LPCTSTR: Long Pointer to Const context-dependent (single-byte or multi-byte) String

  • 在宽字符串中,每个单个字符占用 2 个字节的内存,包含该字符串的内存位置的长度必须是 2 的倍数。所以如果要在字符串的末尾添加一个宽 '\0',你应该添加两个字节。

  • 抱歉这部分,我不了解 ATL,我无法在这部分为您提供帮助,但实际上我认为这里没有复杂性,而且我认为它很容易维护。您真正想让哪些代码更易于理解和维护?

于 2012-02-10T14:05:54.393 回答
1
  1. 如果 BYTE* 表现得像一个正确的字符串(即最后一个 BYTE 是 0),您可以将 BYTE* 强制转换为 LPCSTR,是的。使用 LPCSTR 的函数假定以零结尾的字符串。
  2. 我认为只有在处理一些多字节字符集时才需要多个零。最常见的 8 位编码(如普通的 Windows Western 和 UTF-8)不需要它们。
  3. CString是微软对用户友好字符串的最佳尝试。例如,它的构造函数可以同时处理输入charwchar_t类型输入,而不管 CString 本身是否宽,因此您不必过多担心转换。

编辑:等等,现在我看到他们正在滥用 BYTE 数组来存储宽字符。我不建议这样做。

于 2012-02-10T14:07:02.457 回答
0

LPCWSTR 是每个字符 2 个字节的字符串,“char”是每个字符一个字节。这意味着您不能将其转换为 C 样式,因为您必须调整内存(在每个标准 ASCII 之前添加一个“0”),而不仅仅是以与内存不同的方式读取数据(什么是 C-Cast会做)。所以我会说演员阵容不是那么安全。

双空终止:你总是有 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 操作。

于 2012-02-10T14:07:20.133 回答