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

3

我的问题与这个旧问题有关: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);

上述代码行给我带来了一个连接错误。我相信这是因为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,如果有所改变,我确实可以访问boost库,但我宁愿不使用它们。


SCNd16 只是一个定义,所以如果对于您来说没有跨平台/架构代码的必要,只需查找其值并在 swscanf 字符串中输入 % 后即可。 - lonewasp
2个回答

4
这是一个VS2013编译器的错误。由于它已被标记为“已修复”,可能在VS2015中可以正常工作(我没有安装预览版来尝试)。
你所拥有的代码行
swscanf (line.c_str(), L"Value of integer: %" SCNd16 L"\n", &my_integer);

该代码是格式正确的,因为即使SCNd16扩展为缺少L前缀的字符串字面量,标准规定如果两个相邻的字符串字面量中有一个缺少编码前缀,则它将被视为具有相同编码前缀。

§2.14.5/14 [lex.string]

在第6阶段(2.2)翻译过程中,相邻的字符串字面量将被连接。如果两个字符串字面量具有相同的编码前缀,则生成的连接字符串字面量具有该编码前缀。如果一个字符串字面量没有编码前缀,则将其视为具有与另一个操作数相同的编码前缀的字符串字面量。...


通常,您可以使用预处理器通过使用标记连接来扩展字符串。例如,定义一组类似于此的宏

#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",要么使用您展示的运行时转换解决方案。


0

这只是一个猜测,因为我现在没有时间尝试。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接