调用 mbtowc() 时 gcc 如何决定宽字符集?

Posted

技术标签:

【中文标题】调用 mbtowc() 时 gcc 如何决定宽字符集?【英文标题】:How does gcc decide the wide character set when calling `mbtowc()`? 【发布时间】:2013-03-03 19:06:29 【问题描述】:

根据gcc手册,选项-fwide-exec-charset在编译时指定了宽字符串和字符常量的宽字符集。

但是在运行时通过调用mbtowc() 将多字节字符转换为宽字符时,宽字符集是什么? POSIX standard 表示多字节字符的字符集由当前语言环境的 LC_CTYPE 类别确定,但没有说明宽字符集。我现在手头没有 C 标准,所以我不知道 C 标准对此有何规定。

gcc 选项-fwide-exec-charset 是否像在编译时一样确定mbtowc() 使用的宽字符集?

【问题讨论】:

【参考方案1】:

简答:用于宽字符串的字符集由编译时已知的wchar_t 的特征决定。由于mbtowc 是一个库函数,所以在构建 libc 时会发生这种情况。

mbtowc 从以外部字符集编码的字符串中读取单个字符,并将其写入能够表示任何字符的wchar_t 值。同样,mbstowcs 将一个外部编码的 C 字符串转换为一个简单的 wchar_t 数组。从系统的角度来看,指定生成的宽字符/字符串的“字符集”是没有意义的,因为以任何方式更改其输出编码都会破坏生成的宽字符串作为 wchar_t 数组的使用.

您可以描述 mbstowcs 生成固定宽度的 Unicode 编码,例如 UCS-2 或 UCS-4(或更准确地说是 UTF-16 或 UTF-32),如果宽字符对应于ISO 10646 代码点,取决于wchar_t 的宽度。您还可以将其描述为 little-endian 或 big-endian,具体取决于您对 wchar_t 的处理器表示的字节序。但这些是平台的属性,您无法在运行时更改它们,就像您无法将字节序或 ASCII 更改为 EBCDIC 一样。

-fwide-exec-charset 用于向编译器显式指定与 array-of-wchar_t 的内部表示相对应的字符集。当它与编译器通常生成的表示不同时,这很有用(因为您正在交叉编译,或者因为编译器配置错误)。这就是手册继续警告“您将遇到与wchar_t 不完全匹配的编码问题”的原因。

【讨论】:

根据c preprocessor manual,c预处理器看不到执行字符集而是源字符集。所以-fwide-exec-charset不会影响预处理器。 您提到了交叉编译,我认为这可能是-fwide-exec-charset 存在的原因。 "C: A Reference Manual" 书第 2.1.1 节的最后一段在解释源和执行字符集可能不同时也提到了交叉编译。但是还有一个问题:如果我设置-fwide-exec-charset,那么宽字符串常量的执行字符集可能与调用mbtowc()转换的字符串的执行字符集不同。所以我看不到这个选项有太多用处。 @wbb 仅当您指定了错误的字符集时,它可能会有所不同。它不应该是您自定义的东西,它是修复编译器生成的字符串与 libc 在运行时生成的字符串之间不兼容的最后手段。当配置正确时,-fwide-exec-charset 应该是不必要的(同样,除非在经常看到这种不匹配的情况下进行交叉编译)。

以上是关于调用 mbtowc() 时 gcc 如何决定宽字符集?的主要内容,如果未能解决你的问题,请参考以下文章

GCC(libstdc++)运行时如何决定在异常处于活动状态时终止()

gcc编译器对宽字符的识别

请问如何用C语言实现汉字,和Unicode编码的转换?

cygwin dlopen 错误:多字节或宽字符无效或不完整

计算的列宽与 css 声明的列宽不同。浏览器如何决定宽度?

从 C++ 传递函数指针以由 C# 调用 - 函数参数包括宽字符字符串 (LPCWSTR)