2014-01-14 83 views
0

因此printf()是一个函数,如果发生错误,它将返回写入的字符数(如果成功或负值),查看此示例,输出如预期的那样为为什么printf()在它应该是0时给出随机输出?

#include <stdio.h>  
int main(void) 
{  
printf("%d");  
return 0; 
} 

现在,当我添加一些更多的这些%d的:http://ideone.com/brw5vG 输出更改为: 0 134513819 -1216430092 134513808

我无法弄清楚怎么了随机垃圾值?在输出中也有一个负值,并且负值证明了错误,所以任何人都可以精确地指出这里的错误吗? 请简明扼要。谢谢。

+1

你从来没有真正检查过'printf'的返回值。 – 2014-01-14 19:30:22

+2

'printf'的返回值与它应该写入stdout的内容有很大的区别。两件完全不同的事情。 –

+0

@remyabel:这不是问题。 –

回答

2

您错误地将格式字符串指定为printf这是undefined behavior,您应该对结果没有任何期望。通过指定%d,您告诉printf预计您没有提供的参数int

如果我们看一下C99标准草案部分7.19.6.1fprintf函数又包括pritnf关于格式说明说:

[...]如果对于格式参数不足, [...]

+0

好吧,我明白了,但为什么我们首先得到一个零?我的意思是,如果这是一个“未定义的行为”,那么第一个也应该是一些随机值。 – Am33d

+1

未定义的手段行为未定义。什么事情都可能发生。 – haccks

5

因为"%d"表示预期为整数。你不通过任何,所以你得到未定义的行为。

注意克++ 4.8.2给出一个有用的警告:

警告:格式 '%d' 需要匹配的 'INT' 参数[-Wformat =]

类似地对于铛++ 3.4 :

警告:比数据参数的更多 '%' 转化[-Wformat]

+0

我不指望'printf()'会在这里返回错误结果。并非如此,只是没有现有的实施。 –

+0

@DietrichEpp同意,未定义的行为是未定义的行为。 – juanchopanza

1

问题在于你如何提出问题;你认为它“应该是0”。事实是,这是未定义的行为,并且printf将替代%d,无论堆栈中发生什么。

3

预期产量为零

printf("%d"); 

为你的程序调用不确定的行为,您不应该期望什么。

(C99,7.19.6.1p2)“[...]如果该格式的参数不足,则行为为 未定义。[...]]”

+0

+1标准参考。 –

1

你的代码调用未定义行为任何可能发生

C11标准说,在部分7.21.6格式的输入/输出功能:。

如果任何参数不是相应转换规范的正确类型,行为未定义。

您没有传递相应的%d说明符的参数。

+0

但为什么我们第一个得到一个零? – Am33d

+2

@SyedAmeedul:未定义的行为意味着*任何事情都可能发生*。有一个零打印是*任何事情发生*的一个例子。问“为什么”是毫无意义的。 –

+0

正如我所说在UB的情况下可能会发生任何事情。无法保证第一个地方的值总是为0。结果可能会改变编译器与编译器之间的差异,甚至可能因编译器的不同版本而异。 – haccks

0

手头有两个问题:第一个原因是编译器为什么没有发出关于printf()这个坏的错误的错误,第二个原因是你得到垃圾输出。我会一次回答一个。

printf()是一个棘手的功能。尽管大多数函数传递给它们的参数数量不变,但printf()却不同。 例如,如果我们把这个简单的功能:

int max(int a, int b) { 
    if (a > b) return a; 
    else return b; 
} 

你可以看到,这个函数总是接收2个参数。这也是编译器知道的事情,并且在编译代码时执行。这就是为什么诸如max(4)这样的呼叫不起作用的原因。编译器会看到我们传递的是max() 1个参数而不是2,它会发出一个错误。

printf()是一个接受可变数量参数的函数,这个数量由格式字符串中的格式说明符(以%开头)的数量来确定。这意味着编译器无法在编译时知道传递给printf的参数数量是否足够(或者可能太多)。

你被垃圾打印的原因是因为函数如何读取它们的输入参数。函数的所有输入参数都驻留在堆栈上。在调用该函数之前将这些函数压入堆栈,然后由函数进行处理。在这种情况下,printf()期望除格式字符串之外还有一个额外的参数(因为%d),所以它会查找第二个参数可能已经存在的地址。唉,这个论点没有通过,所以它实际上会查看堆栈中可能包含其他任何东西(返回地址,帧指针,封闭范围的局部变量或其他)的地方。

你可以阅读更多关于函数调用如何工作here

+1

*这意味着编译器无法在编译时知道您传递给printf的参数量是否足够*这是错误的。当格式字符串是一个字符串文字时,就像在OP例子中一样,什么会阻止编译器知道结尾参数的数量是不正确的? – ouah

+0

那么这是相当详细的,但谢谢 – Am33d

+0

当格式字符串是一个文字是编译器知道的特殊情况。但是,在一般情况下,它不知道。 – ehudt

相关问题