printf()'神秘地'知道我打算打印什么?

TGI*_*key 13 c printf

我忘了将附带的变量添加到printf()调用中.printf()如何知道我想要打印的内容?

int successful = 0;//Flag
printf("\nEnter a number to search for: ");
scanf("%d", &data);
successful = search(list, data);
successful? printf("\n'%d' was found\n\n", data) : printf("\n'%d' was NOT found\n\n");
Run Code Online (Sandbox Code Playgroud)

违规代码是最后一行三元表达式的最终"else".我已经运行了几十次,似乎总是在输出中打印正确的参数.

: printf("\n'%d' was NOT found\n\n");
Run Code Online (Sandbox Code Playgroud)

这怎么还每次都有效?

lus*_*oog 19

它似乎可行,但不要依赖于此.

它可能有效,因为你最近的函数调用,

successful = search(list, data);
Run Code Online (Sandbox Code Playgroud)

data值保留在堆栈上的适当位置.


这里可能有用的是,如果你忽略在声明单个局部变量的函数中包含一个return语句,则有时会出现类似的偶然性.

int wowee () {
    int val;
    val = 12;

    // <-- no return statement!
}
Run Code Online (Sandbox Code Playgroud)

有时,val将返回局部变量,可能是由于相同类型的堆栈重用.但这也是未定义的行为,即使它恰好起作用.


这两种情况的道德标准是启用更多的编译器警告.编译器可以诊断这样的问题,即使检查格式字符串类型传递给变量的匹配prinf -家庭功能.


Die*_*Epp 12

哎呦!这是"未定义的行为".

printf("\n'%d' was NOT found\n\n"); // undefined behavior
Run Code Online (Sandbox Code Playgroud)

"未定义的行为"是一个技术术语,基本上意味着...... 任何事情都可能发生.也许正确的事情可能发生,也许程序会崩溃,或者它可能会完全做其他事情.

在这种情况下,你想要的值可能已经在正确的位置堆栈,所以当printf()何时获取它的参数时它得到了正确的值.这在很大程度上取决于优化的使用和您正在使用的特定ABI,特别是,并非所有ABI都将值放在堆栈上以进行非可变函数调用.

successful = search(list, data);
//                        ^^^^ places "data" on stack as second argument
Run Code Online (Sandbox Code Playgroud)

如果将程序编译为64位,它可能不再起作用,因为最常见的x64 ABI使用寄存器来表示前四个非可变参数.

它不会改变您的代码错误的事实,如果您想要始终如一地获得正确答案,则需要修复它.

  • 我只是在等待一个gcc扩展,它根据未定义的行为格式化开发人员的硬盘驱动器. (4认同)