31

我尝试了以下代码:

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
4

7 回答 7

27

我怀疑 GCC (mingw) 有自定义代码来禁用printf对 Windows 上的广泛功能的检查。这是因为微软自己的实现(MSVCRT)是严重错误的,并且对于广泛的功能具有%s%ls 倒退;printf由于 GCC 无法确定您是否将链接到 MS 的损坏实现或一些更正的实现,所以它可以做的最不显眼的事情就是关闭警告。

于 2013-07-17T14:13:35.233 回答
19

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

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

于 2013-07-17T13:26:20.797 回答
6

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

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

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

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

于 2015-09-04T06:12:55.170 回答
5

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

至于没有编译器警告,printf 使用变量参数列表,只有第一个参数可以进行类型检查。编译器并非旨在解析格式字符串并类型检查匹配的参数。对于像 printf 这样的函数,这取决于程序员

于 2014-01-30T22:11:08.193 回答
1

man fprintf

   C      (Not in C99 or C11, but in SUSv2, SUSv3, and SUSv4.)  Synonym for lc.  Don't use.

   S      (Not in C99 or C11, but in SUSv2, SUSv3, and SUSv4.)  Synonym for ls.  Don't use.

因此,不要使用 %C 或 %S,而是始终使用 %lc 或 %ls。

于 2021-11-26T19:10:09.077 回答
1

答案 A

上面的答案都没有指出为什么您可能看不到某些打印件。这也是因为您在这里处理的是流(我不知道这一点)并且流有一种叫做方向的东西。让我从这个来源引用一些东西:

窄方位和宽方位

新打开的流没有方向。第一次调用任何 I/O 函数都会确定方向。

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

窄 I/O 函数不能在面向宽的流上调用;宽 I/O 函数不能在面向窄的流上调用。宽 I/O 函数在宽字符和多字节字符之间转换,就像调用mbrtowcwcrtomb 一样。与在程序中有效的多字节字符串不同,文件中的多字节字符序列可能包含嵌入的空值,并且不必以初始移位状态开始或结束。

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


答案 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;
}
于 2020-02-06T04:29:44.620 回答
0

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

等效的符合 C99 的格式说明符是%sand %ls

于 2013-07-17T13:25:56.827 回答