首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >mbtowc在osx上总是返回一个字节

mbtowc在osx上总是返回一个字节
EN

Stack Overflow用户
提问于 2012-11-27 02:26:48
回答 2查看 691关注 0票数 2

我已经在文件系统中搜索了不可移植的名称中的字符。为此,我使用mbtowc函数来检查每个字符。

在OSX上,我尝试过:

//在OSX上

代码语言:javascript
复制
#include <iostream>

using namespace std;

int main(int argc, const char * argv[])
{
string s1 = "Ä";
size_t len = s1.length();           // will be 2, ok


const char* s1c = s1.c_str();       // 0xC3 0x84 0x00, ok

char a = s1[0];                     // 0xc3, ok
char b = s1[1];                     // 0x84, ok

mbtowc(NULL,NULL,0);                // reset

wchar_t wc;
int mb_len = mbtowc(&wc,s1c,len);   // mb_len = 1, wc=0xc3 00 00 00
                                    // why only one byte?
                                    // how can i get the right Wchar???
char mb2[10];
int mblen2 = wctomb(mb2,wc);        // mblen2 = 1; mb2 = 0xC3

string s2 = string(mb2);            // len = 1 only 0xC3


return 0;
}

为什么mbtows对所有的char只返回1?

赫伯特

EN

回答 2

Stack Overflow用户

发布于 2012-11-27 03:23:38

您的程序在C语言环境中启动,它将字符串视为ASCII (或未指定的ASCII兼容的8位编码)。因此,mbtowc()只是将字符串中的第一个字节复制到wchar_t中。您需要在使用UTF-8的语言环境中调用setlocale(LC_CTYPE, locale),因为您的源代码是以UTF-8编码的,因此字符串常量也是如此。

setlocale(LC_CTYPE, "")使用用户的当前语言环境设置,因此如果您要读取用户提供的文件,它是合适的;但是,如果有人试图在不使用UTF-8语言环境的机器上运行您的程序,您的示例可能会失败。您可以改用setlocale(LC_CTYPE, "UTF-8"),这是一种始终使用UTF-8的语言环境(我不相信它是标准化的,但至少在我的Mac和Linux机器上是存在的)。

下面是一个例子(为了简单起见,这次使用纯C语言,而不是C++ )。我添加了一些printfs来显示正在发生的事情。它在调用setlocale()之前和之后运行相同的mbtowc()

代码语言:javascript
复制
#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <stdlib.h>

void test_mbtowc(char *s) {
  size_t len = strlen(s);
  wchar_t wc;

  mbtowc(NULL,NULL,0);
  int mb_len = mbtowc(&wc,s,len);
  printf("%d, %08x\n", mb_len, wc);
}

int main()
{
  char *s = "Ä";

  printf("%02hhx %02hhx %02hhx\n", s[0], s[1], s[2]);
  test_mbtowc(s);

  setlocale(LC_CTYPE, "UTF-8");
  test_mbtowc(s);

  return 0;
}

这是输出。如您所见,我们将字符串编码为UTF-8。对mbtowc的第一个调用只是简单地复制第一个字节;mb_len1,我们得到的结果是c3。第二个代码给出了2的mb_lenc4,这是Äwc中的Unicode码点。

代码语言:javascript
复制
c3 84 00
1, 000000c3
2, 000000c4
票数 2
EN

Stack Overflow用户

发布于 2012-11-27 03:55:56

mbtowc()使用C语言环境来确定要在其间进行转换的编码。C语言环境总是以"C"开头,这不能保证支持基本字符集(ASCII码支持的抽象字符集的一个子集)之外的任何字符。

默认情况下,OS在其他任何地方都使用UTF8,因此mbtowc()不会在您期望的编码之间进行转换。

您可以将C语言环境设置为使用适当编码的语言环境。如果您在C++程序中执行此操作,则可能应该通过设置C++全局区域设置(这将反过来设置C区域设置)来完成此操作:

代码语言:javascript
复制
std::locale::global(std::locale("en_US.UTF-8")); // locale names are not portable

但是,扰乱区域设置通常不是一件好事。全局语言环境本质上是一个全局变量,并且有所有反对使用它的正常原因。它有广泛的影响,例如,它可以影响sprintf()在某些库中的一些使用,这些库可能依赖于没有被设置为某些地区。此外,对区域设置敏感的函数可能不是线程安全的和/或可重入的。

OS X有一个“扩展区域设置支持”库(标题<xlocale.h>),其中包含*_l版本的区域设置敏感函数,这些函数采用额外的区域设置参数,而不是使用全局区域设置。这解决了全球语言环境的许多问题。我相信它甚至被用来在OS上实现许多标准的C++语言环境功能。

代码语言:javascript
复制
locale_t loc = newlocale(LC_ALL_MASK, "en_US.UTF-8", NULL);
char buf[MB_CUR_MAX_L(loc)];
mbstate_t state = {};  
wcrtomb_l(buf, L'A', &state, loc);
freelocale(loc);

iconv是一个允许在大量编码之间直接转换的API。C++还支持在某些编码之间进行转换,特别是使用wstring_convert模板和一些标准编解码器方面(codecvt_utf8、codecvt_utf8_utf16)在各种Unicode编码(UTF-8、UTF-16和UTF-32)之间进行转换。

当然,只有当您确实需要在编码之间进行转换时,所有这些才重要。目前还不清楚这是否仅仅是为了“在文件系统中搜索不可移植的名称中的字符”。如果您有一个您认为合法的代码点列表(或一个非法的代码点列表),那么在UTF-8字符串中直接搜索这些代码点的UTF-8编码应该不是那么困难,不需要进行转换。

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

https://stackoverflow.com/questions/13570891

复制
相关文章

相似问题

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