繁体   English   中英

将 wchar_t 转换为 char

[英]Convert wchar_t to char

我想知道这样做是否安全?

wchar_t wide = /* something */;
assert(wide >= 0 && wide < 256 &&);
char myChar = static_cast<char>(wide);

如果我很确定宽字符将落在 ASCII 范围内。

为什么不直接使用库例程wcstombs

您正在寻找wctomb() :它符合 ANSI 标准,因此您可以信赖它。 即使wchar_t使用大于 255 的代码,它也能工作。您几乎肯定不想使用它。


wchar_t一个整数类型,所以如果你真的这样做,你的编译器不会抱怨:

char x = (char)wc;

但是因为它是一个整数类型,所以绝对没有理由这样做。 如果您不小心阅读了Herbert Schildt 的 C: The Complete Reference任何基于它的 C 书籍,那么您就完全被误导了。 字符应该是int或更好的类型。 这意味着你应该这样写:

int x = getchar();

而不是这个:

char x = getchar(); /* <- WRONG! */

就整数类型而言, char毫无价值。 您不应该创建采用char类型参数的函数,也不应该创建char类型的临时变量,同样的建议也适用于wchar_t

char*对于字符串来说可能是一个方便的 typedef,但是将其视为“字符数组”或“指向字符数组的指针”是新手错误——尽管cdecl工具是这样说的。 将其视为实际的字符数组,如下所示:

for(int i = 0; s[i]; ++i) {
  wchar_t wc = s[i];
  char c = doit(wc);
  out[i] = c;
}

错得离谱。 不会做你想做的; 以微妙而严肃的方式打破,在不同平台上表现不同,你肯定会让你的用户感到困惑。 如果你看到这个,你正在尝试重新实现wctombs() ,它已经是 ANSI C 的一部分,但它仍然是错误的

确实在寻找iconv() ,它将字符串从一种编码(即使它打包到wchar_t数组中)转换为另一种编码的字符串。

现在去读这个,了解 iconv 有什么问题。

assert用于确保某些内容在调试模式下为真,而不会在发布版本中产生任何影响。 最好使用if语句并对范围外的字符制定备用计划,除非获得范围外字符的唯一方法是通过程序错误。

此外,根据您的字符编码,您可能会发现 Unicode 字符 0x80 到 0xff 与其char版本之间存在差异。

一个简单的方法是:

        wstring your_wchar_in_ws(<your wchar>);
        string your_wchar_in_str(your_wchar_in_ws.begin(), your_wchar_in_ws.end());
        char* your_wchar_in_char =  your_wchar_in_str.c_str();

我多年来一直使用这种方法:)

我写了一个简短的函数,将 wchar_t 数组打包到 char 数组中。 不在 ANSI 代码页 (0-127) 上的字符将替换为“?” 字符,并正确处理代理对。

size_t to_narrow(const wchar_t * src, char * dest, size_t dest_len){
  size_t i;
  wchar_t code;

  i = 0;

  while (src[i] != '\0' && i < (dest_len - 1)){
    code = src[i];
    if (code < 128)
      dest[i] = char(code);
    else{
      dest[i] = '?';
      if (code >= 0xD800 && code <= 0xD8FF)
        // lead surrogate, skip the next code unit, which is the trail
        i++;
    }
    i++;
  }

  dest[i] = '\0';

  return i - 1;

}

从技术上讲,“ char ”可以与“ signed char ”或“ unsigned char ”具有相同的范围。 对于无符号字符,您的范围是正确的; 从理论上讲,对于签名字符,您的条件是错误的。 实际上,很少有编译器会反对——结果是一样的。

挑剔: assert的最后一个&&是语法错误。

断言是否合适取决于当代码到达客户时您是否能够承受崩溃,以及如果断言条件被违反但断言没有编译到代码中,您可以或应该做什么。 对于调试工作,它看起来不错,但您可能还需要在它之后进行活动测试以进行运行时检查。

这是另一种方法,记住对结果使用 free() 。

char* wchar_to_char(const wchar_t* pwchar)
{
    // get the number of characters in the string.
    int currentCharIndex = 0;
    char currentChar = pwchar[currentCharIndex];

    while (currentChar != '\0')
    {
        currentCharIndex++;
        currentChar = pwchar[currentCharIndex];
    }

    const int charCount = currentCharIndex + 1;

    // allocate a new block of memory size char (1 byte) instead of wide char (2 bytes)
    char* filePathC = (char*)malloc(sizeof(char) * charCount);

    for (int i = 0; i < charCount; i++)
    {
        // convert to char (1 byte)
        char character = pwchar[i];

        *filePathC = character;

        filePathC += sizeof(char);

    }
    filePathC += '\0';

    filePathC -= (sizeof(char) * charCount);

    return filePathC;
}

也可以转换 wchar_t --> wstring --> string --> char

wchar_t wide;
wstring wstrValue;
wstrValue[0] = wide

string strValue;
strValue.assign(wstrValue.begin(), wstrValue.end());  // convert wstring to string

char char_value = strValue[0];

一般来说,没有。 int(wchar_t(255)) == int(char(255))当然,但这只是意味着它们具有相同的 int 值。 它们可能不代表相同的字符。

您甚至会在大多数 Windows PC 中看到这种差异。 例如,在 Windows 代码页 1250 上, char(0xFF)wchar_t(0x02D9) (上面的点char(0xFF)是相同的字符,而不是wchar_t(0x00FF) (带有分音符的小 y)。

请注意,它甚至不适用于 ASCII 范围,因为 C++ 甚至不需要 ASCII。 特别是在 IBM 系统上,您可能会看到'A' != 65

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM