我的问题是关于缺少参数的printf之后的行为:
printf("%s blah blah %d", int); // integer was given as argument (and not int written)
我已经知道如果格式的参数不足,行为就是 未定义。
问题是printf结果或整个程序是否未定义?
修改
澄清我不是在询问编译错误或警告,执行此行时程序也不会崩溃。问题是这行可以使程序在此行已经执行后随机崩溃。
答案 0 :(得分:1)
整个计划未定义。
事实上,即使程序存在,它也是未定义的:未定义编译器本身在文本printf("%s blah blah %d", int);
答案 1 :(得分:0)
基本上是整个计划。 Printf开始从堆栈中取出参数,在这种情况下,值int
值得过多。这通常类似于返回地址。因此,当printf返回时,它将返回到堆栈上接下来的任何随机数。通常的结果 - 如果你很幸运 - 是一个分段错误。
因为它将参数压入堆栈,所以它会将它们弹出,所以它会先尝试获取int
。
如果您不幸运,它会找到一个可寻址的代码块。这导致了第二种情况,其中地址成为随机字符散列的地址。现在它将尝试打印一个字符串,直到找到一个随机的NUL字符。
<强>更新强>
正如约阿希姆所指出的那样,具体细节取决于调用约定,所以让我们做一个明确的例子。当要调用printf函数时,首先按下返回地址或最后按下它。我们假设它首先被推送(在通常的架构上更常见),所以这个调用需要PUSH返回地址,格式字符串的PUSH地址,PUSH是一个int值 - 让我们说42.这给了我们这个堆栈:< / p>
RTN ADDR
ADDR OF STRING
42
并使堆栈指针SP指向堆栈上的下一个位置。
现在printf开始解释字符串。它查找int
参数的地址,并找出它的SP-1。所以string参数的地址必须是SP-2 ...但这是格式字符串的地址,因为没有字符串参数。然后当它查找格式字符串的地址时,它想要找到SP-3,但这是返回地址,可执行代码的地址。在大多数机器上,这应该会导致分段错误。
如果你通过调用约定的其他选项,你会发现每个选项都会看到某些错误的东西,因为无论如何,printf认为它需要引用三个东西堆栈,而不是它的两个。