简体   繁体   English

printf 在 C 中具有多个指针作为 arguments

[英]printf with multiple pointers as arguments in C

What is the behavior of printf() when we supply multiple arguments to it without a format specifier?当我们在没有格式说明符的情况下向它提供多个 arguments 时, printf()的行为是什么?

Example:例子:

int main() 
{
    printf("hello", "hi");
    return 0;
}

Why does the compiler produce a warning on compilation of the above program?为什么编译器在编译上述程序时会产生警告? :

warning: too many arguments for format [-Wformat-extra-args]

If we compile the similar program below:如果我们编译下面类似的程序:

int main() 
{
    char *s1 = "hello";
    char *s2 = "hi";
    printf(s1, s2);
}

No warnings are produced.不会产生任何警告。 What is the reason for this?这是什么原因?

Also, why do both programs output hello only, and don't also print hi ?另外,为什么两个程序 output 只hello ,而不打印hi

The C 2018 standard specifies the behavior of printf in clause 7.21.6.3, in which paragraph 2 says “The printf function is equivalent to fprintf with the argument stdout interposed before the arguments to printf .” The C 2018 standard specifies the behavior of printf in clause 7.21.6.3, in which paragraph 2 says “The printf function is equivalent to fprintf with the argument stdout interposed before the arguments to printf .”

The standard specifies the behavior of fprintf in 7.21.6.1, which tells us the second argument (the first argument of printf ) is a format string and that it may contain various conversion specifications introduced by the character “%”.该标准在 7.21.6.1 中规定了fprintf的行为,它告诉我们第二个参数( printf的第一个参数)是一个格式字符串,它可能包含由字符“%”引入的各种转换规范。 Thus, in printf("hello", "hi") , "hello" is a format string with no conversion specifications.因此,在printf("hello", "hi")中, "hello"是一个没有转换规范的格式字符串。 In this case, paragraph 2 tells us what happens:在这种情况下,第 2 段告诉我们会发生什么:

If the format is exhausted [fully processed] while arguments remain, the excess arguments are evaluated (as always) but are otherwise ignored.如果格式已用尽 [完全处理] 而 arguments 仍然存在,则会评估多余的 arguments(一如既往),但否则将被忽略。

Thus, in printf("hello", "hi") , "hi" is ignored, and "hello" is a format string that contains only ordinary characters, which are copied to the output stream per paragraph 3.因此,在printf("hello", "hi")中, "hi"被忽略,并且"hello"是一个仅包含普通字符的格式字符串,根据第 3 段将其复制到 output stream 中。

The compiler warns about printf("hello", "hi") because it is able to see that this call contains an excess argument because the format string does not contain a conversion specification for it.编译器警告printf("hello", "hi")因为它能够看到这个调用包含一个多余的参数,因为格式字符串不包含它的转换规范。

Your compiler does not warn about printf(s1,s2);您的编译器不会警告printf(s1,s2); because it does not analyze what s1 will contain during this call.因为它不分析s1在此调用期间将包含的内容。 This sort of analysis is not impossible in this situation, but situations like this are rare: When a programmer uses a pointer to a string as the format string for printf , it is usually a string or pointer that is computed, constructed, or selected during program execution, and the manner of this computation is often beyond the ability of a compiler to analyze.这种分析在这种情况下并非不可能,但这样的情况很少见:当程序员使用指向字符串的指针作为printf的格式字符串时,通常是在执行过程中计算、构造或选择的字符串或指针程序执行,而这种计算的方式往往超出了编译器的分析能力。 Situations where the pointer is clearly a pointer to a fixed string are rare, since they are not frequently useful, so presumably compiler implementors have not found it valuable to implement the code necessary for the compiler to handle these situations.指针明显是指向固定字符串的指针的情况很少见,因为它们并不经常有用,因此可能编译器实现者没有发现实现编译器处理这些情况所需的代码是有价值的。

tl;dr: Extra arguments to printf() are ignored. tl; dr:忽略printf()的额外 arguments。

The official C language standard (the link is to a draft of the C11 version) says the following:官方的C 语言标准(链接是 C11 版本的草稿)说如下:

§ 7.21.6.1 The fprintf function § 7.21.6.1 fprintf function

  1. ... ...

  2. ... If the format is exhausted while arguments remain, the excess arguments are evaluated (as always) but are otherwise ignored. ...如果格式已用尽,而 arguments 仍然存在,则会评估多余的 arguments(一如既往),否则将被忽略。 The fprintf function returns when the end of the format string is encountered.当遇到格式字符串的结尾时, fprintf function 返回。

... and printf() is simply fprintf() targeted at the standard output file. ...而printf()只是针对标准 output 文件的fprintf()

About your two code snippets:关于您的两个代码片段:

  • The compiler is giving you a hint, for the first snippet, that the number of arguments doesn't match the number of specifiers in the format string.对于第一个片段,编译器会提示您 arguments 的数量与格式字符串中的说明符数量不匹配。 It's just a courtesy - it's not required to notice this.这只是一种礼貌 - 不需要注意这一点。 This also explains why the compiler does not notice it for the second snippet.这也解释了为什么编译器没有注意到第二个片段。 It could , but it's too much effort to chase your pointers and check what they point at.可以,但是追逐您的指针并检查它们指向的内容太费力了。

  • In both cases, your format string is your first argument to printf() , ie "hello" .在这两种情况下,您的格式字符串都是printf()的第一个参数,即"hello" That string has no format specifiers, so the printf() looks at the "hello" , and understands it only needs to print that and doesn't need process any other arguments.该字符串没有格式说明符,因此printf()查看"hello" ,并理解它只需要打印它,不需要处理任何其他 arguments。 That's whi it ignores "hi" .这就是它忽略"hi"的原因。

The first parameter of printf is the format string, because printf is about printing formatted data. printf的第一个参数是格式字符串,因为printf是关于打印格式化数据的。 To specify how to format the data, printf uses the first argument.要指定如何格式化数据, printf使用第一个参数。 This is different from other languages and libraries where all the parameters (like Python's print ) are used in the same way and formatting is done through other means.这与其他语言和库不同,其中所有参数(如 Python 的print )都以相同的方式使用,并且通过其他方式完成格式化。

The first and second examples you provide are both "incorrect" although technically valid because you are passing a format string that does not need any extra argument, so "hi" is unused.您提供的第一个和第二个示例都是“不正确的”,尽管在技术上是有效的,因为您传递的格式字符串不需要任何额外的参数,因此"hi"未被使用。

What you may want to do instead is:您可能想要做的是:

printf("%s %s", "hello", "hi");

many compilers know well very well the printf function family and read compile time the format string analysing the parameters.许多编译器非常了解printf function 系列并读取编译时分析参数的格式字符串。 printf("hello",s2); compiler see that there is no %... in the format string and does not expect any other parameters.编译器看到格式字符串中没有%...并且不需要任何其他参数。 Warning is issued发出警告

if you call printf(s1,s2);如果你调用printf(s1,s2); compiler does not know what is the content of the s1 and it cannot go through the format string and no warning issued.编译器不知道s1的内容是什么,它不能通过格式字符串 go 并且没有发出警告。

Many compilers have special extension to inform them that your function is printf like and you want compiler to read the format string - gcc:许多编译器具有特殊的扩展名,以通知他们您的 function 与printf类似,并且您希望编译器读取格式字符串 - gcc:

      extern int
      my_printf (void *my_object, const char *my_format, ...)
            __attribute__ ((format (printf, 2, 3)));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM