【问题标题】:can there be less number of fomat specifier than the number of variables in a printf statement格式说明符的数量是否可以少于 printf 语句中的变量数量
【发布时间】:2014-02-09 12:45:08
【问题描述】:

我在 borland c 编译器中编写了以下程序。我怀疑为什么 c 编译器在编译时或运行时都没有抛出任何错误。程序执行良好,输出为 2 4。

#include<stdio.h>
#include<conio.h>
int main(){
int a=2,b=4,c=6;
printf("%d%d",a,b,c);
getch();
return 0;
}

即使格式说明符的数量少于参数的数量,也不会引发错误。这里发生了什么。

【问题讨论】:

  • 它只是将前两个格式说明符替换为前两个变量值
  • 获得更好的编译器:ideone.com/4cNhCg.
  • 这就是为什么他们说启用编译器警告会有所帮助。
  • 我认为这里重要的是printf 只是一个普通函数,它(通常)不会得到编译器的特殊处理。在它的核心编译器不必在格式说明符和参数之间建立任何关联——它所看到的只是一个字符串和一堆将在运行时进行评估的参数——并且可能会很乐意接受诸如尝试printf a float"%d" 等。虽然现在有一些编译器和代码分析工具会警告你。
  • @user2802841 'printf' 接受带有 '%d' 的 'float' 值,但对于以下代码,输出很奇怪。 '浮点数=5.0; printf("%d",a);输出为 0'。

标签: c format format-specifiers


【解决方案1】:

格式说明符的数量可以少于 printf 语句中的变量数量吗

答案是肯定的。来自 C 标准:

(c99, 7.19.6.1p2) "如果格式用尽而参数仍然存在,多余的参数将被评估(一如既往),否则将被忽略。"

【讨论】:

  • 这在 C 2011 中是一样的,只是它是 7.21.6.1 2。
【解决方案2】:

这可以正常工作,但如果您的编译器设置为检查printf varargs 参数,则可能会出现编译器错误。

printf 函数是可变参数,即采用可变数量的参数。格式字符串将指示使用了多少,如果您指定太多,它们将被忽略。 POSIX 参考是:http://pubs.opengroup.org/onlinepubs/009695399/functions/printf.html 声明:

如果格式已用尽而参数仍然存在,则应评估多余的参数,否则将被忽略。

(底层 C 引用是来自 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf 的 C 2011 7.21.6.1 2 - 感谢 @EricPostpischil - 但这是一个 701 页的 PDF)

然而,从可变参数函数的工作原理来看,这一点相当明显。

相反(变量少于格式说明符)是不允许的,因为printf 函数将尝试访问堆栈中不存在的变量,从而给出未定义的行为。

【讨论】:

  • 那不是 C 引用;它是 POSIX (IEEE 1003.1) 参考。它旨在与 C 保持一致,但对 C 不具有权威性。C 参考是 C 2011 7.21.6.1 2。
  • @EricPostpischil - 很公平。为了改进我的答案,是否有更好的(即 HTML)直接引用 C 标准(而不是它的衍生物)。我有open-std.org/jtc1/sc22/wg14/www/standards.html#9899 引用的open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf,但作为一个701 页的PDF,它对于指向人们来说并不友好。
  • 您可以“非正式地”引用任何来源来回答问题,只要您不说它是 C 的“参考”。但我发现 C 标准在大多数情况下都非常易读。起初它令人生畏,因为它的组织方式与许多人谈论 C 甚至在课堂上教授它的方式不同,而且它使用不同的术语(例如,“对象”而不是“变量”)。但这些差异很有用,因为它们是为技术精度而设计的。因此,熟悉该标准是值得的。按照标准进行教学的人可以帮助提高他人的知识。
  • @EricPostpischil 谢谢。 我已经阅读它没有困难。我只是希望有一个像 POSIX 一样的在线 HTML 版本,这样我就可以将人们(可能会被吓倒)直接指向相关部分,而不是需要下载的 PDF 页面。
  • 另外,700 页的大部分是图书馆和附件。核心语言包含在前 180 页中。
【解决方案3】:

是的。

http://www.cplusplus.com/reference/cstdio/printf/

“这些参数的数量至少应与格式说明符中指定的值的数量一样多。函数会忽略其他参数。”

【讨论】:

  • 那是 C++ 标准,而不是 C 标准。这是一道C题。我意识到答案是一样的。
  • @abligh:C++ 标准遵循 C 标准来定义 C 标准库函数。
  • @OliCharlesworth 我知道。但是鉴于提问者在 POSIX 下问了一个关于 C 的问题,而不是 C++,这不是引用 C 标准(或 POSIX 标准)而不是 C++ 标准的正确答案(即使它确实遵循 C 标准)。我没有否决答案...
  • @abligh:它甚至不是 C++ 标准。这是一个关于C++的第三方网站,注册给Juan Soulie。
【解决方案4】:

虽然您向printf() 提供了三个变量,但只有两个格式说明符,所以这两个被替换为前两个可用变量。

【讨论】:

  • 不是我,但可能是因为你回答了printf("%d%d",a,b,c);的具体情况,而OP想要一个通用的答案
  • @FilipeGonçalves - 也许你是对的,尽管我认为我的可以根据我提供的具体解释进行概括!
【解决方案5】:

因为你的函数接受可变数量的参数

int printf ( const char * format, ... );

在 C 中,这意味着没有参数类型检查,而且,printf 不知道用户传递给函数的参数有多少。有一个技巧 - printf 计算 % 的数量并确定它是参数的数量。要了解它是如何工作的,您可以查看va_listva_start va_endva_arg。尝试运行printf("%i,%i,%i", a); - 未定义的行为。

【讨论】:

  • 他为什么要运行调用未定义行为的代码?
  • Amm,要了解 printf(大多数可变参数函数)只关注 format arg 并且不知道实际参数计数。显示这个是不好的方法吗?
  • 对我来说这是一个糟糕的方法,因为您从具有未定义行为的代码中得出的任何结论都是无效的 - 根据定义,未定义行为意味着任何事情都可能发生。
  • 这回答了错误的问题。该问题询问的转换说明符少于格式字符串后的参数。 printf("%i", a, a) 没有未定义的行为(假设 a 具有合适的类型)。
  • 最新 C 标准:7.16.1.1 va_arg 宏:如果没有实际的下一个参数,或者类型与实际的下一个参数的类型不兼容(根据默认参数提升),行为未定义
猜你喜欢
  • 2021-12-25
  • 1970-01-01
  • 2014-05-04
  • 1970-01-01
  • 2020-09-30
  • 2020-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多