【问题标题】:Convert a 'const wchar_t *' to 'unsigned char *'将 'const wchar_t *' 转换为 'unsigned char *'
【发布时间】:2011-10-02 02:49:38
【问题描述】:

在 C++ 中是否可以将 'const wchar_t *' 转换为 'unsigned char *'?

我该怎么做?

wstring dirName;
unsigned char* dirNameA = (unsigned char*)dirName.c_str();

// I am creating a hash from a string
hmac_sha256_init( hash, (unsigned char*)dirName.c_str(), (dirName.length)+1 );

【问题讨论】:

  • 是的。您希望如何存储和使用结果?输入是什么样的?
  • 您应该计算字符串的 UTF-16 编码版本或其他字符集的 HMAC 吗? (UTF-8、latin1、Windows-1252 等?)(根据字符编码,你会得到不同的 HMAC,在这一点上你的答案也各不相同!)
  • 可能是错误的问题:您要转换 TYPE 还是 MEANING?如果你想转换类型,你应该按照 Larry 的建议使用强制转换。您可能真正想要的是将 Windows UTF-16 字符串转换为其他字符串,然后这里的人们问的问题是:还有什么?具体来说? (UTF-8?根据您的代码页进行一些 ISO-x 编码?等等)

标签: c++ winapi unicode


【解决方案1】:

您需要逐个字符转换。有像wcstombs 这样的功能可以做到这一点。

【讨论】:

  • 老实说,我认为这没有必要。为什么不能对原始 unicode 数据使用 SHA-256?假设你有正确的长度,它不会因为任何特殊原因而工作吗?
  • @ChrisLutz 最初的问题是关于将const wchar_t * 转换为unsigned char *。你是对的,你可以只取散列,但如果我没有提到如何在宽字符串和字符串之间切换,我会失职
  • 您完全按照要求回答了问题,但您在这里错过了真正的问题(如何将此函数与此字符串一起使用),并可能提供误导/危险的建议。首先转换为 ANSI 是危险的,因为许多 unicode 字符串在转换中可能会折叠为相同的值(您最终会得到 ? 或其他替换字符),并且最终会得到相同的哈希值。例如,如果当前的代码页是西方代码页,那么所有相同长度的中文字符串都会以相同的散列结尾,这在某种程度上违背了散列的初衷。
  • @BrendanMcK:谁说过 ANSI?这不是wcstombs 所做的。
  • 抱歉,我应该说“任何非 Unicode 代码页”,而不是专门说 ANSI。在几乎任何代码页中折叠代码点都会遇到同样的问题。但是 ANSI 与某些 MBCS 不是这里的问题。我提出的关键点仍然是:使用 wctombs,您最终可能会丢失信息并最终得到错误或无用的哈希值 - 取决于输入数据与当前语言环境。
【解决方案2】:

尝试使用 reinterpret_cast。所以:

unsigned char * dirNameA = reinterpret_cast<unsigned char *>(dirName.c_str());

这可能不起作用,因为 c_str 返回一个 const wchar_t *所以你也可以尝试:

unsigned char * dirNameA = reinterpret_cast<unsigned char *>(
                               const_cast<wchar_t *>(dirName.c_str())
                           );

这是可行的,因为 hmac_sha256_init 应该接受二进制 blob 作为其输入,因此 dirName 中包含的 unicode 字符串是可接受的哈希输入。

但是您的代码中有一个错误 - dirName.length() 返回的长度是字符数,而不是字节数。这意味着向 hmac_sha256_init 传递的字节太少,因为您将 unicode 字符串作为二进制 blob 传递,因此您需要将 (dirName.length()) 乘以 2。

【讨论】:

  • 注意:这会导致哈希在不同平台上给出不同的结果。
  • @Don Reba:即使该程序仅适用于 Windows,它也可能与其他系统通信并期望 HMAC 匹配。例如,如果您将文件上传到 Amazon S3,如果您计算的 HMAC 与服务器不同,您的上传将被拒绝。
  • 简单地转换字符串是不够的。 wchar_t 类型可以表示 UTF-16 或 UTF-32 字符串(甚至是另一种特定于平台的编码)。转换为char* 可能会导致具有相同逻辑内容的多个字符串根据所使用的编码或其细节产生不同的结果。正确的方法是使用平台提供的编码/解码功能来保证一致的表示。
  • Unicode 字符串散列需要一些思考。 (我假设 wstring 是 Unicode,如果不是,那么 HMAC 真的不再有意义)。基本上 U+00C1 Á 等于 U+0041 U+0301 Á 并且因此应该具有相同的 HMAC。你最好使用 Unicode 规范化(“NFC”)
  • @MSalters:你完全正确。而且我怀疑提问者并没有真正想到创建 unicode 字符串的哈希意味着什么。对于那些说“UTF-8”的人来说,UTF-8 只是一种应用于 unicode 字符串的压缩算法——它与 MSalters 提出的问题相同。
【解决方案3】:

由于您使用的是 WinAPI,请使用WideCharToMultiByte

【讨论】:

  • 不是一个好主意;请参阅 Foo Bah 的回答下的讨论。根据您转换到的输入字符串和代码页,您最终可能会将输入文本折叠为替换字符,从而导致低质量的哈希值。 (例如,如果你转换成ANSI并且输入的是中文,那么所有相同长度的字符串将只是替换字符的相似长度的字符串,从而产生相同的哈希值。)
猜你喜欢
  • 2015-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-23
  • 1970-01-01
  • 2011-12-11
相关资源
最近更新 更多