printf,wprintf,%s,%S,%ls,char *和wchar *:编译器警告未宣布错误?

问题描述 投票:24回答:6

我尝试了以下代码:

wprintf(L"1 %s\n","some string"); //Good
wprintf(L"2 %s\n",L"some string"); //Not good -> print only first character of the string
printf("3 %s\n","some string"); //Good
//printf("4 %s\n",L"some string"); //Doesn't compile
printf("\n");
wprintf(L"1 %S\n","some string"); //Not good -> print some funny stuff
wprintf(L"2 %S\n",L"some string"); //Good
//printf("3 %S\n","some string"); //Doesn't compile
printf("4 %S\n",L"some string");  //Good

并且我得到以下输出:

1 some string
2 s
3 some string

1 g1 %s

2 some string
4 some string

所以:wprintfprintf似乎都能够正确打印char *和wchar *,但前提是要使用精确的说明符。 如果使用了错误的说明符,则可能不会出现编译错误(也不会发出警告!),并最终导致错误的行为。您是否遇到相同的行为?

注意:这是在Windows下测试的,使用MinGW和g ++ 4.7.2编译(我将在以后检查gcc)

编辑:我也尝试了%ls(结果在注释中)

printf("\n");
wprintf(L"1 %ls\n","some string"); //Not good -> print funny stuff
wprintf(L"2 %ls\n",L"some string"); //Good
// printf("3 %ls\n","some string"); //Doesn't compile
printf("4 %ls\n",L"some string");  //Good
c mingw
6个回答
24
投票

我怀疑GCC(mingw)具有自定义代码,以禁用对Windows上广泛的printf功能的检查。这是因为Microsoft自己的实现(MSVCRT)严重错误,并且对于广泛的%s功能具有%lsprintf backwards。由于GCC不能确定您是要链接到MS的已损坏的实现,还是要更正一些错误的实现,因此它可以做的最不引人注意的事情就是关闭警告。


18
投票

格式说明很重要:“%s”表示下一个字符串是一个窄字符串(“ ascii”,通常每个字符8位)。 “%S”表示宽字符字符串。将两者混合会产生“不确定的行为”,其中包括打印垃圾,只有一个字符或什么都没有。

打印一个字符是因为宽字符为16位宽,并且第一个字节为非零,然后为零字节->窄字符串中字符串的结尾。这取决于字节顺序,在“大端”计算机中,您根本不会得到任何字符串,因为第一个字节为零,而下一个字节包含非零值。


4
投票

至少在Visual C ++中:printf(和其他ACSII函数):%s代表一个ASCII字符串%S是Unicode字符串wprintf(和其他Unicode函数):%s是Unicode字符串%S是ASCII字符串

就没有编译器警告而言,printf使用可变参数列表,只有第一个参数可以进行类型检查。编译器并非旨在分析格式字符串并类型检查匹配的参数。如果使用printf之类的功能,则取决于程序员]


4
投票

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

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

在类Unix平台中,s和S与Windows平台具有相同的含义。

参考:https://msdn.microsoft.com/en-us/library/hf4y5e3w.aspx


0
投票

[%S似乎符合The Single Unix Specification v2,并且也是当前(2008)POSIX specification的一部分。

等效的符合C99的格式说明符将为%s%ls


0
投票

答案

以上答案均未指出为什么您看不到某些印刷品。这也是因为在这里您要处理流((我不知道)],并且流具有称为定向的东西。让我从this来源中引用一些内容:

窄而宽的方向

新打开的流具有无方向。首次调用任何I / O功能确定方向。

广泛的I / O功能使流面向广泛,窄的I / O功能使流面向狭窄。设置后,只能使用freopen更改方向。

窄I / O不能在面向广泛的流上调用函数;宽I / O不能在狭窄的流上调用函数。宽输入/输出函数在宽字符和多字节字符之间进行转换,就像通过呼叫mbrtowcwcrtomb。与多字节字符串不同在程序中有效的文件中的多字节字符序列可能包含嵌入的null,而不必以初始换档状态。

因此,一旦使用printf(),您的方向就会变得狭窄,从这一点开始,您将无法从wprintf()中获得任何东西,而您确实没有。除非您以某种方式使用打算在文件上使用的freeopen()


问题

[谁能提供有关如何使用freeopen()语言环境的示例吗?如果这不可能,那么我们需要一直坚持[C0​​]或printf()


推荐问答