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

时间:2013-07-17 13:14:24

标签: c mingw

我尝试过以下代码:

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

6 个答案:

答案 0 :(得分:22)

我怀疑GCC(mingw)有自定义代码来禁用对Windows上的宽printf函数的检查。这是因为Microsoft自己的实现(MSVCRT)严重错误并且%s%ls 向后用于广printf个函数;由于海湾合作委员会无法确定你是否会与MS的破坏实施或一些纠正的实施相关联,所以它能做的最不突兀的事情就是关闭警告。

答案 1 :(得分:17)

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

打印一个字符,因为宽字符例如是16位宽,第一个字节是非零,后跟零字节 - >窄字符串中的字符串结尾。这取决于字节顺序,在“大端”机器中,你根本就没有字符串,因为第一个字节是零,下一个字节包含一个非零值。

答案 2 :(得分:4)

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

就没有编译器警告而言,printf使用可变参数列表,只能对第一个参数进行类型检查。编译器不是为解析格式字符串而设计的,而是检查匹配的参数。在像printf这样的函数的情况下,这取决于程序员

答案 3 :(得分:3)

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

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

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

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

答案 4 :(得分:0)

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

符合C99标准的格式说明符为%s%ls

答案 5 :(得分:0)

答案A

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

窄而宽的方向

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

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

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

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


答案B

事实证明,您可以像这样使用freeopen()

freopen(NULL, "w", stdout);             

再次使流“未定义” 。试试这个例子:

#include <stdio.h>
#include <wchar.h>
#include <locale.h>

int main(void)
{
    // We set locale which is the same as the enviromental variable "LANG=en_US.UTF-8".
    setlocale(LC_ALL, "en_US.UTF-8");

    // We define array of wide characters. We indicate this on both sides of equal sign
    // with "wchar_t" on the left and "L" on the right.
    wchar_t y[100] = L"?€ο Δικαιοπολις εν αγρω εστιν\n";

    // We print header in ASCII characters
    wprintf(L"content-type:text/html; charset:utf-8\n\n");

    // A newly opened stream has no orientation. The first call to any I/O function
    // establishes the orientation: a wide I/O function makes the stream wide-oriented,
    // a narrow I/O function makes the stream narrow-oriented. Once set, we must respect
    // this, so for the time being we are stuck with either printf() or wprintf().

    wprintf(L"%S\n", y);    // Conversion specifier %S is not standardized (!)
    wprintf(L"%ls\n", y);   // Conversion specifier %s with length modifier %l is 
                            // standardized (!)

    // At this point curent orientation of the stream is wide and this is why folowing
    // narrow function won't print anything! Whether we should use wprintf() or printf()
    // is primarily a question of how we want output to be encoded.

    printf("1\n");          // Print narrow string of characters with a narrow function
    printf("%s\n", "2");    // Print narrow string of characters with a narrow function
    printf("%ls\n",L"3");   // Print wide string of characters with a narrow function

    // Now we reset the stream to no orientation.
    freopen(NULL, "w", stdout);

    printf("4\n");          // Print narrow string of characters with a narrow function
    printf("%s\n", "5");    // Print narrow string of characters with a narrow function
    printf("%ls\n",L"6");   // Print wide string of characters with a narrow function

    return 0;
}