如何将 uint16_t 转换为宽字符串 (std::wstring)

How to convert uint16_t to a wide string (std::wstring)

我的问题与这个较旧的问题有关 Format specifiers for uint8_t, uint16_t, ...?

只是回顾一下原始问题是关于如何使用 scanf 的 uint8_t、uint16_t、uint32_t 和 uint64_t 的说明符?

问题的答案如下:

sscanf (line, "Value of integer: %" SCNd32 "\n", &my_integer);

但有谁知道如何做到这一点,但会产生一个宽字符串?

std::wstring line;
swscanf (line.c_str(), L"Value of integer: %" SCNd16 L"\n", &my_integer);

第 sbove 行给我一个连接错误。我相信是因为 SCNd16 不适用于宽弦?

目前我的解决方案是在原始答案中创建 std::string 然后将其转换为宽字符串

sscanf_s(line.c_str(), "%" SCNd16 "\n", &sixteenBitInteger)
// code here to check for EOF and EINVAL
//then I convert it 
typedef std::codecvt_utf8<wchar_t> ConverterType; 
std::wstring_convert<ConverterType, wchar_t> converter;
std::wstring convertedString = converter.from_bytes(line);

但它相当丑陋,我相信一定有更完美的方式来进行这种转换? 如果它有助于理解我的使用,我正在使用 uint16_t 类型来存储 Web 服务器的端口号,但我希望能够将其转换为宽字符串,因为这是预期的显示类型。如果 C++11 完全改变了答案,我也使用 C++11,我确实可以访问 boost 库,尽管我不想使用它们。

纯属猜测,因为我目前没有时间尝试。

能否使用预处理器将宽字符串 L 标记粘贴到展开的 SCNd16 的前面?

这是一个VS2013 compiler bug。由于它已被关闭为 "fixed",也许它会在 VS2015 中工作(没有安装预览来试一试)。

你的代码行

swscanf (line.c_str(), L"Value of integer: %" SCNd16 L"\n", &my_integer);

格式正确,因为即使 SCNd16 扩展为缺少 L 前缀的字符串文字,标准规定如果在两个相邻的字符串文字中,一个缺少编码前缀,它被视为具有与另一个相同的编码前缀。

§2.14.5/14 [lex.string]

In translation phase 6 (2.2), adjacent string literals are concatenated. If both string literals have the same encoding-prefix, the resulting concatenated string literal has that encoding-prefix. If one string literal has no encoding-prefix, it is treated as a string literal of the same encoding-prefix as the other operand. ...


通常,您可以使用预处理器通过标记连接来加宽字符串。例如,定义一组这样的宏

#define WIDEN_(x) L##x
#define WIDEN(x) WIDEN_(x)

并将有问题的代码行转换为

swscanf (line.c_str(), L"Value of integer: %" WIDEN(SCNd16) L"\n", &my_integer);

会解决这个问题,但由于实现细节,它在 VS2013 上没有。 SCNd16 宏实际上扩展为两个单独的字符串文字 - "h" "d"。所以上面的宏加宽了第一个文字,但不是第二个,你 运行 进入相同的(伪造的)错误。

您的选择是硬编码字符串 "hd" 或使用您展示的 运行 时间转换解决方案。