使用窄字符串的Swprintf()

swprintf() with narrow strings

本文关键字:Swprintf 字符串      更新时间:2023-10-16

下面这行代码在Visual Studio 2010中会产生垃圾:

swprintf(buf, L"Value is %s", "abcd");

但是,相同的代码在Linux上运行良好。

通过尝试,我可以通过在Visual Studio中使用%S而不是%S来使它工作。

swprintf(buf, L"Value is %S", "abcd");

我想知道这是Visual Studio 2010中的一个bug还是我错过了一些东西。问候。

这是一个"bug",尽管这种行为是设计出来的。宽字符串printf和scanf函数的初始visualc++实现早于它们在C中的标准化,并且在某些情况下,其行为偏离了C标准库规范的要求。

在C标准库规范中,%s%c格式修饰符必须始终与char数组或元素配对,l长度修饰符必须在提供wchar_t数组或元素时使用。

在这些函数的Visual c++实现(文档)中,%s%c格式说明符需要一个相应的"自然"宽度参数。对于窄字符串printf和scanf函数,需要一个char指针或元素,对于宽字符串函数,需要一个wchar_t指针或元素。要传递"other"宽度的字符串,可以使用%S%C格式说明符。或者,hl长度修饰符可用于显式指定string参数是窄字符串还是宽字符串。

在其他优点中,这些函数的visualc++实现可以很容易地通过<tchar.h>中的_TCHAR映射将旧代码迁移到使用Unicode字符串。不幸的是,标准化的内容与Visual c++实现中已经实现的内容不同(我不熟悉这里的历史;可能是标准化的内容与另一个实现相匹配。

微软对printfscanf函数的实现不符合标准,因此在Linux(符合标准)和Windows(不符合标准)上得到不同的结果。

Matt在他的回答中发布的链接指向一个MSDN页面,暗示了这种不当行为:

C、S和Z类型字符,以及 C和S类型字符在与printf和wprintf函数一起使用时的行为,都是Microsoft扩展,并且与ANSI不兼容。Visual c++不支持F类型字符。

我特别强调。顺便说一句:这里的ANSI指的是所有的C标准,以及扩展后的c++标准。

具体的问题是,MS重新定义了这些转换说明符(c s),期望在与宽函数一起使用时使用UTF-16。

%s与%s含义不同:

s:与printf函数一起使用时,指定一个单字节或多字节字符串;当与wprintf函数一起使用时,指定一个宽字符串。字符将显示到第一个空字符或直到达到精度值。

S:与printf函数一起使用时,指定一个宽字符串;当与wprintf函数一起使用时,指定单字节或多字节字符串。字符将显示到第一个空字符或直到达到精度值。

这就是为什么

swprintf(buf, L"Value is %S", "abcd");

显示正确的值。

MSDN链接在这里

"abcd"是一个很窄的字符串,因为您省略了'L'。Swprintf()期望它的所有%s字符串输入都是宽的