在 C++ {fmt} 库中显示 Unicode 字符

问题描述 投票:0回答:4

我想显示无穷大符号

,它具有Unicode
U+221E
。我目前正在使用 fmt 库,它应该有很多支持并且是跨平台的。

fmt::print("", fmt::styled("∞ >", fmt::emphasis::bold | fg(fmt::color::aquamarine)));

我得到以下输出:

? >

我也尝试过设置:

setlocale(LC_ALL, "en_US.UTF-8");
没有帮助。我使用的是 Windows 11 x64。

警告:

warning C4566: character represented by universal-character-name '\u221E' cannot be represented in the current code page (1252)

MS Visual Studio 2022 IDE。

我应该在项目属性中更改字符集吗?当前设置为:使用 Unicode 字符集,第二个选项是:使用多字节字符集

c++ unicode fmt
4个回答
2
投票

要使其与 MSVC 一起使用,您需要使用

/utf-8
标志进行编译。除此之外,这会将字符串文字编码设置为 UTF-8。它由 {fmt} 检测到,它使用 Unicode API 写入控制台。一般来说,更改区域设置不会有帮助,因为问题在其他地方:

  1. 您的字符串文字编码(有时称为执行编码)与您的源编码不匹配 - 这就是导致警告的原因。
  2. 控制台使用单独的代码页(编码)。

出于类似的原因,使用宽字符串也无济于事。


0
投票

问题出在编译期间,而不是运行时。 您在字符串文字中按原样指定

字符,但编译器正在使用代码页 1252 解析源代码,该代码页不支持 Unicode U+221E(并且该字符无法存储在单个
char 中)无论如何)。因此,在编译过程中您会丢失 
,在 fmt 库看到它之前,它会被 
?
 替换。

setlocale()

 对此问题没有影响,因为它仅在运行时处理。

项目的字符集选项对这个问题也没有影响,因为它只影响基于

TCHAR

的API的编译,没有其他影响。

所以,你有2个选择:

  • 确保您的源代码以 UTF-8 格式保存,并使用指定的

    /utf8

     编译器标志进行编译。

  • 使用宽字符串代替,例如:

fmt::print(L"", fmt::styled(L"∞ >", fmt::emphasis::bold | fg(fmt::color::aquamarine)));
    

-1
投票
首先,Unicode 格式有不同类型。您可能正在尝试打印 UTF8 版本的无穷大符号,但 Windows 默认使用 UTF16,因此您会得到疯狂的文本。其实和

fmt

没有任何关系。

对于初学者,在 C++11 及更高版本上,您可以使用以下代码将

cout

cerr
 等使用的字符集更改为 UTF8:

#include <locale> template <typename StreamT> void set_utf8_locale(StreamT& stream) { std::locale loc(std::locale(), new std::codecvt_utf8<typename StreamT::char_type>()); stream.imbue(loc); } set_utf8_locale(std::cout);
然后您需要确保您的编译器将字符串存储为 UTF8。您可以通过在字符串前添加前缀 

u8

 来实现此目的,例如 
u8"abc"

在 C++20 及更高版本中,这会产生与 const char* 不同的类型,因此您需要使用

reinterpret_cast<const char*>(u8"abc")

 来获取正确的类型。

Linux 和 MacOS 使用 UTF8 进行输出,因此您无需为这些平台担心这一点。


-1
投票
您的错误是

C4566。出现这种情况是因为 Unicode 格式,尤其是非标准 ASCII 字符 在 C++ 中变得疯狂。

这个:

char inf = '∞'

因为没有分配足够的位而中断。同样的事情也发生在 
string inf = '∞'
string inf = L'∞'
 等等..

最方便的做法是使用宽字符(

wchar_t

)和数组,以便能够呼吸。
可能还有另一种方法可以做到这一点,但这是我使用 inifity 符号/Unicode 符号的方法。

wchar_t inf[] = L"\u221e"; // ∞ in unicode is U+221E
窄字符串(一字节字符)会转换为多字节字符,而宽字符串(两字节字符)则不会。这是因为 L 将字符串转换为宽文字,用外行人的话说,这为更多字符腾出了空间位,这样它们就不会变得奇怪..

© www.soinside.com 2019 - 2024. All rights reserved.