如何在控制台中使用动态字符串与UTF-8一起使用?

时间:2014-06-19 12:50:28

标签: c++ windows utf-8 console-application iostream

SO上的大多数answersquestions用于将L置于任何UTF-8字符串之前。我发现没有解释它是什么,在源代码中,常量是根据我的IDE在winnt.h中定义的。

这是我如何使用它,而不知道它是什么:

std::wcout<<L"\"Přetečení zásobníku\" is Stack overflow in Czech.";

显然,常量连接不能应用于变量:

void printUTF8(const char* str) {
  //Does not make the slightest bit of sense
  std::wcout<<L str; 
}

那么它是什么以及如何将其添加到动态字符串中?

3 个答案:

答案 0 :(得分:1)

L表示C编译器该字符串由“宽字符”组成。在Windows中,这些将是UTF-16 - 您放入字符串的每个字符都是16位,或两个字节,宽:

L"This is a wide string"

相反,UTF-8字符串始终是由字节组成的字符串。 ASCII字符(A-Z 0-9等)按照它们一直以来的方式进行编码 - 在0x00到0x7F(或0到127)的范围内。国际字符(如ř)使用0x80到0xFF范围内的多个字节进行编码 - wikipedia有一个非常好的解释。优点是它可以使用普通的C字符串表示。

"This is an ordinary string, but also a UTF-8 string"

"This is a C cedilla in UTF-8: \xc3\x87"

但是,如果您在实际代码中输入这些国际字符,您的编辑器需要知道您输入的是UTF-8,因此它可以正确编码字符 - 就像上面的C cedilla一样。然后该字符串将正确传递给您的函数。

在您的情况下,您的评论表明您使用的是UTF-16。在这种情况下,还有另外两个问题:

  • 默认情况下,控制台不会正确输出Unicode字符。您需要将字体更改为truidaype字体,如Lucida Console

  • 您还需要将输出模式更改为Unicode UTF-16。你可以这样做:

    _setmode(_fileno(stdout),_ O_U16TEXT);

代码示例:

#include <iostream>
#include <io.h>
#include <fcntl.h>

int wmain(int argc, wchar_t* argv[])
{
    _setmode(_fileno(stdout), _O_U16TEXT);
    std::wcout << L"Přetečení zásobníku is Stack overflow in Czech." << std::endl;
}

答案 1 :(得分:1)

L""是一个WIDE字符串。也就是说,它是一个wchar_t[1]。 UTF-8字符串不能宽,因为它们是多字节(可变长度)。 VC ++略有错误,并且使得宽字符串可变长度,精确到UTF-16。但通常他们是UTF-32。

多字节字符串的问题在于有许多不同的编码,而UTF-8只是其中之一。 Windows实际上本身不支持UTF-8编码。例如MessageBoxA()可以使用任何编码但UTF-8。只有一个例外,那就是MultiByteToWideChar(CP_UTF8, ...),这就是你需要的。

答案 2 :(得分:0)

重新提出实际问题

  

[L前缀]是什么以及如何将其添加到动态字符串中?

这与我写这篇文章时的问题标题非常不同,即“如何在控制台中使用动态字符串与UTF-8一起工作?”

简而言之, UTF-8 是Unicode的编码,其中基本编码单位是8位,通常称为字节(更确切地说,它是一个八位字节),而{{ 1}}前缀形成字符或字符串文字,其中编码单位通常为16或32位 - 在Windows中为16位,与原始Unicode一样。

宽字符或字符串文字基于L类型而非wchar_t

在Windows中,宽字符串编码为 UTF-16 。最常见的六万个Unicode字符用单个char值表示,但有些很少使用中文表意文字等,需要两个连续的wchar_t值,称为代理对

在Windows中使用16位编码单元是在1992年左右建立的。我不确定何时采用UTF-16(作为当时UCS-2编码的扩展),它只是稍后。 所以这是在C99要求宽字符集的所有字符都应该用单个wchar_t值表示之前建立的。这一要求似乎是一种纯粹的政治策略,确保没有Windows C编译器可以正式符合,这是一种仅适用于Unix-land的通用ISO编程语言标准。不幸的是,由于C ++ 11基于C99,我们现在也在C ++ 11中使用它,确保没有Windows C ++编译器可以完全符合。纯白痴。如果你问我。

勘误 ,重新删除上面的文字:根据Wikipedia’s article about it,单个wchar_t的字词对于“扩展”中的任何字符都足够了字符集“已经在C90中了。这使得Windows与C和C ++标准之间的不兼容性成为微软的错,而不是C委员会的错。它似乎仍然是政治性的,并且相当愚蠢,但是(开明)与其他人相比应该比我最初维持的还要严重......


使用宽动态字符串的一种方法是使用wchar_t标题中的std::wstring

使用Visual C ++,您可以使用 <string> 函数而不是标准wmain,这是获取宽命令行参数的简便方法。

MinGW64(IIRC)g ++也支持

main,尽管还不是普通的MinGW g ++,如g ++ 4.8.something。但是,就Windows API而言,它很容易实现。除非你需要严格的符合标准的代码来提供特殊的主要功能特性,例如能否使用参数声明它,但是嘿,让我们对事物有所了解。


使用Visual C ++ 12.0和g ++ 4.8.2编译好的示例:

wmain

请注意,对于Windows ANSI源,除非使用适当的编译器选项指定源编码,否则不会使用g ++编译。