使用窄字符串的Swprintf()
swprintf() with narrow strings
下面这行代码在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
格式说明符。或者,h
和l
长度修饰符可用于显式指定string参数是窄字符串还是宽字符串。
在其他优点中,这些函数的visualc++实现可以很容易地通过<tchar.h>
中的_TCHAR
映射将旧代码迁移到使用Unicode字符串。不幸的是,标准化的内容与Visual c++实现中已经实现的内容不同(我不熟悉这里的历史;可能是标准化的内容与另一个实现相匹配。
微软对printf
和scanf
函数的实现不符合标准,因此在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字符串输入都是宽的