gpt4 book ai didi

c - 代码是如何工作的?

转载 作者:行者123 更新时间:2023-12-01 08:57:13 25 4
gpt4 key购买 nike

下面的代码是用 C 编写的。当给定一组输入数字时,它会跳过第一个数字,并打印其余数字。

main(i)  
{
if(~scanf("%d",gets(&i)))
printf("%d\n",i),main();
}

我想知道,这段代码是如何工作的?

EDIT: For those of you, who think it does not work http://www.ideone.com/cENzy

最佳答案

此代码在 C 中是不合法的。main 必须采用零个、两个或三个参数。一个参数不是合法的选项。 获取 在堆栈上涂鸦。坦率地说,如果这能奏效那就是奇迹了——未定义的行为比比皆是!

话虽如此,让我们看一下在 x86 上编译 C 代码的典型方式,以了解其工作原理。首先,main(i) 是一个旧的 K&R 风格的声明。它被解释为 int main(int i),但没有设置真正的原型(prototype) - 因此将来对 main 的调用不会对其参数进行类型检查。回想一下,在 x86 上,参数是通过在调用目标函数之前将它们压入堆栈来传递的。因此,如果我们的参数数量错误,它不会崩溃(假设您使用的是这种 ABI!),而只是提供虚假数据。

另请注意,在 x86 上,堆栈向下增长 - 当您调用函数时,当前堆栈指针减少。这意味着,如果您在这些参数之一之上破坏了内存,您将破坏属于调用函数的内存,并且在您返回之前可能不会注意到。

现在让我们看看执行流程。 gets(&i) 首先执行,并且(假设编译器忽略类型不匹配!)获取一行文本,并将它存储到覆盖调用者堆栈帧的堆栈上! 这里假设一个堆栈在内存中向下增长;在向上增长的堆栈上,这将根据字符串的长度覆盖 gets 的返回地址并可能崩溃。

尽管 gets 抓取了一行文本,但该文本将被忽略并丢弃。这是因为gets的返回值,即&i,会被传递给scanf。所以 scanf 读取一个整数并将其存储在 i 中。没问题。 scanf 然后返回 1,它是二进制否定的某个负非零值,这是真的,所以 printf 然后打印该值。然后,逗号运算符用于再次递归调用 main,并使用错误数量的参数(参数通常会使用一些虚假值进行初始化),这就像一个循环。

请注意,在 scanf 返回后,换行符保留在输入中未被使用,因此 gets 会在下一次处理它。另请注意,当 EOF 发生时,scanf 将返回 EOF (0xFFFFFFFF),逻辑取反为 0。main 将返回,并迅速崩溃,因为其调用者的堆栈已可能被 gets 覆盖。

总而言之,这是一个巧妙的 hack,但高度依赖于未定义的行为。请不要在真实代码中模仿这一点。

关于c - 代码是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5063748/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com