printf() 在没有双引号的情况下工作,打印随机字符 [重复]
Posted
技术标签:
【中文标题】printf() 在没有双引号的情况下工作,打印随机字符 [重复]【英文标题】:printf() working without double quotes, prints random characters [duplicate] 【发布时间】:2018-06-05 16:18:36 【问题描述】:我在大学测试中偶然发现了这段 C 代码,当我在 Dev-C++ 5.11 编译器上测试它时,它打印出随机字符。我不明白这段代码是如何工作的,或者为什么工作。有人可以启发我吗?
int main()
char a[10] = "%s" ;
printf( a ) ;
【问题讨论】:
如果它打印随机字符,你怎么能断言它“有效”?因为它编译? 除非您编写了一个旨在随机生成字符并打印它们的程序,否则我不会称打印随机字符工作。 尝试去掉变量“a”并将字符串直接放入 printf() 调用中,这应该很明显发生了什么。 真正的问题是为什么要编译? 因为 C 很幼稚。它认为程序员知道自己在做什么。 【参考方案1】:这个问题有两部分:缺少的引号和随机字符。
printf()
只是一个函数。您可以将字符串和其他值作为参数传递给函数。您不必使用文字。您可以同时使用char *a = "something"; printf(a)
(将变量作为参数传递)和printf("something")
(将字符串文字作为参数传递)。
printf()
也是 variadic function。这意味着它可以接受任意数量的参数。您可以使用printf("hello world")
、printf("%s", "hello world")
甚至printf("%s %s", "hello", "world")
。一些较旧的编译器不会根据第一个参数(即格式字符串)验证您实际上传递了正确数量的参数。这就是为什么您的代码即使缺少参数也能编译的原因。当程序运行时,代码会遍历格式字符串,看到"%s"
并查找第二个参数以将其打印为字符串。由于没有第二个参数,它基本上读取随机内存并且你得到垃圾字符。
【讨论】:
【参考方案2】:printf
函数签名是:
int printf(const char *format, ...);
它期望格式字符串作为第一个参数和可变数量的参数,这些参数根据格式字符串中的格式说明符进行处理和打印。您的问题中的变量 a
正在为其提供格式字符串。随机字符的原因是缺少格式说明符 %s
的参数。以下将正确打印一个字符串:
printf( a, "Hello World!" );
可以在此处查看格式说明符列表https://en.wikipedia.org/wiki/Printf_format_string
为什么会编译?
因为printf
接受的可变参数是在运行时处理的。并非所有编译器都会针对格式字符串验证参数进行编译时检查。即使他们这样做了,他们也最多会抛出一个警告,但仍然会编译程序。
【讨论】:
在这个问题的情况下,格式字符串是动态的:在调用printf
时,格式字符串是数组a
在此时修改的任何内容。在这种情况下,大多数编译器都无法警告格式字符串不匹配,尽管这个在线 C 解释器可以:taas.trust-in-soft.com/tsnippet/t/af45e0e6。编译器最多可以警告格式字符串是动态的,但这并不是系统性错误。
@PascalCuoq 非常酷的编译器!【参考方案3】:
它使用字符串“%s”作为格式字符串,使用未初始化的内存作为“数据”。
它做“某事”的唯一原因是因为编译器显然不够聪明,无法识别格式字符串需要一个参数而提供了零个参数。或者因为编译器警告被忽略和/或错误被关闭。
仅供任何遇到此问题的人参考:“始终启用所有警告和错误并修复您的代码,直到它们消失为止”这并不能保证正确的行为,但确实降低了“神秘”问题的可能性。
【讨论】:
感谢您的快速回复以上是关于printf() 在没有双引号的情况下工作,打印随机字符 [重复]的主要内容,如果未能解决你的问题,请参考以下文章
SHELL脚本攻略(学习笔记)--1.2 echo和printf打印输出