【问题标题】:What's the endianness of iOS wchar_t?iOS wchar_t 的字节序是什么?
【发布时间】:2012-05-30 12:15:30
【问题描述】:

我是我的 iOS 5.1 应用程序,我使用第 3 方库,它使用 wchar_t 作为字符串。这在内部工作正常,但我有时需要为这样的字符串创建一个NSString。我可以使用以下 API:

- (id)initWithBytes:(const void *)bytes length:(NSUInteger)length encoding:(NSStringEncoding)encoding

但是我应该使用什么编码?由于 iOS 中的wchar_t 是 32 位,因此候选编码为:

NSUTF32StringEncoding
NSUTF32BigEndianStringEncoding
NSUTF32LittleEndianStringEncoding

我应该使用哪个字节顺序?我应该使用long NSHostByteOrder()的结果对应的编码字节顺序吗?

顺便问一下,NSUTF32StringEncoding 代表的是哪个字节顺序?它会检查字节并推断字节顺序吗?将 from NSString 转换为 getBytes:maxLength:usedLength:encoding:options:range:remainingRange: 会产生什么结果?

请注意,这里我并不关心平台之间的数据交换(尽管我可能有一天也不得不面对这个问题)。

谷歌搜索并没有多大帮助。

我的直觉是这是编译器定义的,例如当我编写时,我的编译器(CLang)使用什么编码:

wchar_t *s = L"string with non ascii unicode characters such as éèüçß";

当然,编写一个小示例程序并找出答案很容易,但我想要一个不依赖于我的编译器的具体实现的解决方案。

如果你认为我很困惑,那是因为我有点。

【问题讨论】:

  • 你想多了。该库将被编译以使用 C 编译器的终结性。 NSUTF32StringEncoding 对于大多数事情都应该没问题。如果您要导出到非 iOS 主机,游戏会发生变化。
  • 在这种情况下,您需要添加一个选项来导出文件。您的导出文件格式应该是 big-endian 以与网络字节顺序兼容。
  • @starbolin:NSUTF32StringEncoding有问题,尤其会在NSString->wchar_t方向造成问题。

标签: ios string cocoa unicode character-encoding


【解决方案1】:

这就是为什么无法推荐wchar_t 的原因,除非您需要直接使用 Windows API。

在 iOS 上,wchar_t 是具有本机字节顺序的 UTF-32。这在技术上与NSUTF32StringEncoding 不同,后者表示带有 BOM 的字节顺序。

这是我上次回答这个问题时的一些复制意大利面 (link):

#include <machine/endian.h>
#if BYTE_ORDER == BIG_ENDIAN
#define WCHAR_ENCODING NSUTF32BigEndianStringEncoding
#elif BYTE_ORDER == LITTLE_ENDIAN
#define WCHAR_ENCODING NSUTF32LittleEndianStringEncoding
#endif

使用NSUTF32StringEncoding 的问题在于它只能将wchar_t 转换为NSString,但不一定反过来。它会将 BOM 贴在前面(不受欢迎),甚至可能以错误的字节序为您提供数据。

即使从wchar_t 到NSString,使用NSUTF32StringEncoding 也可能会导致错误,但这极不可能。

【讨论】:

  • @Dietrich Epp 为什么 BOM 不受欢迎?没有它你会遇到这样的问题:stackoverflow.com/questions/6458708/…
  • @LuisCien:BOM 仅适用于文档的开头。如果您使用 NSUTF32StringEncoding 转换为 wchar_t,然后执行正常的字符串操作(例如 wprintf),您将在整个文档中得到多个 U+FEFF 字符。请记住,U+FEFF 只是文档开头的 BOM,如果你在其他地方有它,它是一个零宽度的无间断空间。你也不想要像wcslen(L"A") = 2 这样的奇怪东西。简而言之,BOM 在一般情况下在字符串中是不可取的。
  • @LuisCien: 或者换句话说,wchar_t 在 iOS 上是不是 UTF-32,如果你添加了一个 BOM,那么你编码的字符串 不正确. iOS 上wchar_t 的正确编码是UTF-32LE。
  • @Dietrich Epp:啊,有道理。谢谢你的解释。
【解决方案2】:

正如已经指出的,假设 wchar_t* 字符串是 UTF-32 编码的并不安全。

如果您对此非常关心并希望它尽可能健壮,请使用 wcstombs_l() 将 wchar_t* 字符串转换为 UTF-8 编码的 char* 字符串。使用 newlocale() 指定“UTF-8”语言环境。这将可靠地将 wchar_t* 字符串转换为 UTF-8 编码的 char* 字符串。您可以使用 mbstowcs_l() 转换回来。

一旦你有了一个 UTF-8 编码的 char*,你应该准备好使用 NSUTF8StringEncoding 进行 NSString 转换。是的,这是一个额外的箍。跳过它。

【讨论】:

  • 一般来说不安全。但是,它在 iOS 上是安全的。
  • 除了为什么假设 wchar_t* 字符串是 UTF-32 编码的不安全,因为它是 32 位的?这是因为 UCS-4 和 UTF-32 之间的细微差别吗?还是我缺少什么?
  • 另外,如果“假设”不安全,wcstombs_l 将如何在没有“假设”的情况下做到这一点?它会检查文本以查找 BOM 吗?
  • @DietrichEpp 正如之前指出的那样,wchar_t* 不应该有 BOM,它可能在也可能不在 UTF-32 字符串中。此外,UTF-32 仍然有转义字符和元字符; wchar_t* 字符串中不会出现这些。更不用说其他 Unicode 奇怪的东西,比如将字符和代码点与多个位置组合在一起。
  • 感谢您的评论。如果您有时间再做一个,我真的很想知道为什么“假设 UTF-32 == Unicode == wchar_t* 会导致错误和不安全的代码”。对我来说 wchar_t* is UTF-32,我真的看不到任何替代方案。
猜你喜欢
  • 2010-09-30
  • 2019-06-13
  • 1970-01-01
  • 2019-07-18
  • 1970-01-01
  • 2022-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多