2014-05-09 23 views
4

下面的代码行给出了垃圾与Visual Studio 2010:的swprintf()窄弦

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

然而,同样的代码工作正常,在Linux上。

通过试用,我可以在Visual Studio下使用%S代替%s。

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

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

+0

这是一个罕见的问题,它可以并且应该合法地标记C++和C. – Deduplicator

+0

@Deduplicator C和C++看似普遍的一些库函数确实在它们之间有一些差异。除非OP完全确定两种语言的答案是相同的,并且有一个具体的原因是为什么单个语言标签不够用,我认为OP仅仅将它标记为C++是正确的。 – hvd

+0

@ hvd:我并不是暗示OP是粗鲁的或者是错误的,只是在这种情况下C同样适用。因此,我建议添加C.如果我给你不同的印象,我很抱歉。 – Deduplicator

回答

4

这是一个“错误”,虽然行为是通过设计。宽字符串printf和scanf函数的初始Visual C++实现早于C中的标准化,并且在某些情况下,行为会偏离C标准库规范所要求的行为。

在C标准库说明书中,%s%c格式说明必须始终与一个char阵列或元件配对,并且提供了一种wchar_t阵列或元件时,必须使用在l长度改性剂。

在这些函数(documentation)的Visual C++实现中,%s%c格式说明符需要“自然”宽度的相应参数。对于窄字符串printf和scanf函数,需要指针或元素,而对于宽字符串函数,则需要wchar_t指针或元素。要传递“其他”宽度的字符串,可以使用%S%C格式说明符。或者,可以使用长度修饰符hl来明确指定字符串参数是窄字符串还是宽字符串。

除了其他优点之外,这些函数的Visual C++实现使得可以通过the _TCHAR mappings in <tchar.h>轻松迁移旧代码以使用Unicode字符串。不幸的是,标准化的内容与已经在Visual C++实现中实现的标准不同(我不熟悉这里的历史;可能标准化与另一个实现相匹配)。

+0

UCS-2在移动到UTF-16之前; UTF-8也是Unicode。至少同样不幸的是,他们转而使用UCS-2而不是UTF-8。 – Deduplicator

+0

它是在那个时候发明的,但这并没有改变这个事实,即它是不幸的恕我直言。另外,它并没有改变只假装UTF-16是unicode的事实至少是误导性的。 – Deduplicator

0

%s和%S具有不同的含义:

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

这就是为什么

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

显示正确的值。

MSDN链接是here

+0

这并不能解释OP的观察结果,尽管你至少得到了一半的解释。 – Deduplicator

+0

这个答案应该指出,'%s'的这种解释并不符合C99标准。 –

0

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

3

Microsoft实现的宽printfscanf功能不符合标准的,因此你会得到不同的结果在Linux(符合标准的)和Windows(打破)。当它们与使用printf

的C,S和Z类型的字符,和的C和S型的字符的行为:

The link Matt posted in his answer指向在该行为不端一个MSDN页面提示和wprintf函数,都是Microsoft的扩展,并且不是ANSI兼容的。 Visual C++不支持F型字符。

强调我的。顺便说一句:在这里,ANSI意味着所有的C标准,并扩展C++标准。

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