首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Solaris上将UCS-4转换为多字节

在Solaris上将UCS-4转换为多字节
EN

Stack Overflow用户
提问于 2012-04-26 00:26:23
回答 2查看 702关注 0票数 0

为什么这段代码:

代码语言:javascript
复制
char a[10]; 
wchar_t w[10] = L"ä"; // German a Umlaut
int e = wcstombs(a, w, 10);

返回e == -1?

我在Solaris 11上使用的是Oracle Solaris Studio 10。区域设置是拉丁语-1,其中包含德语Umlauts。我找到的所有文档都表明(对我来说)转换应该成功。

如果我这样做:

代码语言:javascript
复制
char a[10] = "ä"; // German a Umlaut
wchar_t w[10];
int e = mbstowcs(w, a, 10);
e = wcstombs(a, w, 10);

没有错误,但结果是错误的。(大写A的一些变体)

我也尝试了wstostr,得到了类似的结果。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-04-26 01:19:21

1)验证进入wchar_t的值是否正确。生成宽字符串文字的编译器必须将L"ä"从源代码编码转换为宽执行字符集。

2)验证程序的区域设置是否正确。您可以使用printf("%s\n", setlocale(LC_ALL, NULL));实现这一点

我怀疑问题出在1),因为对我来说,即使程序的地区设置不正确,我仍然可以得到预期的输出。为了避免源代码编码的问题,您可以转义非ascii字符,如L"\x00E4"

代码语言:javascript
复制
 1  #include <iostream>
 2  #include <clocale>
 3
 4  int main () {
 5    std::printf("%s\n", std::setlocale(LC_ALL, NULL));   // prints "C"
 6
 7    char a[10];
 8    wchar_t w[10] = L"\x00E4"; // German a Umlaut
 9    std::printf("0x%04x\n", (unsigned)w[0]);             // prints "0x00e4"
10
11    std::setlocale(LC_ALL, "");
12    printf("%s\n", std::setlocale(LC_ALL, NULL));        // print something that indicates the encoding is ISO 8859-1
13    int e = std::wcstombs(a, w, 10);
14    std::printf("%i 0x%02x\n", e, (unsigned char)a[0]);  // print "1 0xe4"
15  }
16

C和C++程序中的字符集

在您的源代码中,您可以使用“源字符集”中的任何字符,它是“基本源字符集”的超集。编译器将字符串和字符字面量中的字符从源字符集转换为执行字符集(或宽字符串和字符字面量的宽执行字符集)。

问题是源字符集是依赖于实现的。通常,编译器只需知道您对源代码使用的编码,然后它就会接受该编码中的任何字符。使用命令行参数来设置源编码,Visual Studio将假设源在用户的代码页中,除非它检测到UTF-8或UTF-16的所谓Unicode签名之一,而Clang当前始终使用UTF-8。

一旦编译器为你的代码使用了正确的源字符集,它就会在“执行字符集”中生成字符串和字符文字。执行字符集是基本源字符集的另一个超集,并且也依赖于实现。GCC使用命令行参数来设置执行字符集,VS使用用户的区域设置,而Clang使用UTF-8。

因为源字符集是依赖于实现的,所以在基本集之外写入字符的可移植方法是使用十六进制编码直接指定要在执行中使用的数值,或者(如果您不使用C89/90)使用通用字符名称(UCN),它将被转换为执行字符集(或在宽字符串和字符文字中使用时的宽执行字符集)。UCN类似于\uNNNN或\ NNNNNNNN,并使用代码点值NNNN或NNNNNNNN指定Unicode字符集中的字符。(请注意,C99和C++11禁止您使用代理代码点,如果您想要来自BMP外部的字符,只需使用\U直接写入字符值。)

源字符集和执行字符集是在编译时确定的,并且不会根据运行程序的系统的区域设置而改变。也就是说,程序区域设置使用不一定与执行字符集匹配的另一种编码。但是,宽执行字符集应该与支持的区域设置使用的宽字符编码相对应。

Solaris Studio的行为

Oracle的Solaris编译器具有非常简单的行为。对于窄字符串和字符文字,没有指定特定的源代码编码,源代码中的字节直接用作执行文字。这实际上意味着执行字符集与源文件的编码相同。对于宽字符文字,使用系统区域设置转换源字节。这意味着您必须使用区域设置编码来保存源文件,以便获得正确的宽文字。

我怀疑您的源代码是以非语言环境指定的编码保存的,因此您的编译器无法从L"ä"生成正确的宽字符串文字。您的编辑器可能正在使用UTF-8。您可以使用以下程序进行检查。

代码语言:javascript
复制
 1  #include <iostream>
 2  #include <clocale>
 3
 4  int main () {
 5    wchar_t w[10] = L"ä"; // German a Umlaut
 6    std::printf("0x%04x 0x%04x\n", (unsigned)w[0], (unsigned)w[1]);
 7  }
 8

由于wcstombs可以正确地将宽字符0x00E4转换为拉丁编码'ä‘,因此您希望上面的代码显示0x00E4 0x0000。如果源代码编码是UTF-8,那么您应该看到0x00C3 0x00A4

票数 3
EN

Stack Overflow用户

发布于 2012-04-26 01:18:26

您可能需要设置区域设置才能理解德语。具体地说,您需要ctype facet。

试试这个:

代码语言:javascript
复制
setlocale( LC_ALL, ".1252" );

或者具体地说:

代码语言:javascript
复制
setlocale( LC_CTYPE, ".1252" );

您可能需要搜索比".1252“更好的代码页。祝好运。

上面的代码页示例是Windows。在Unixy系统上,尝试使用"de_DE“作为代码页。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10319810

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档