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打印输出

如何在没有双引号的情况下修复 JSON 键值?

如何在没有双引号的情况下生成光滑的查询?

如何在不输入双引号的情况下制作搜索栏?

在没有插入操作的情况下在 html 文本区域中输入引号和双引号在数据库中失败。可能吗?

SQL中啥情况下用引号