C 给定堆栈和寄存器的状态,我们可以预测printf未定义行为的结果吗

C 给定堆栈和寄存器的状态,我们可以预测printf未定义行为的结果吗,c,gcc,compilation,undefined-behavior,C,Gcc,Compilation,Undefined Behavior,下面是一些用于课堂测验的简单C代码: #include <stdio.h> int main() { float a = 2.3; printf("%d\n", a); return 0; } 然后printf的输出是1606417352。我知道当使用不正确的说明符时,输出是未定义的。出于好奇,我希望这个未定义行为的输出与运行堆栈或寄存器中的一些内存相关,但我还没有弄清楚如何关联它 那么,哪个地址或寄存器用于设置这个printf的输出?换句话说,给定正在运行的堆栈的状

下面是一些用于课堂测验的简单C代码:

#include <stdio.h>

int main() {
  float a = 2.3;
  printf("%d\n", a);
  return 0;
}
然后printf的输出是1606417352。我知道当使用不正确的说明符时,输出是未定义的。出于好奇,我希望这个未定义行为的输出与运行堆栈或寄存器中的一些内存相关,但我还没有弄清楚如何关联它

那么,哪个地址或寄存器用于设置这个printf的输出?换句话说,给定正在运行的堆栈的状态和所有寄存器的所有值,我们可以预测这种未定义行为的输出吗?如果是,那么如何预测这种未定义行为的输出呢?

在AMD64上,除了Windows之外,几乎所有系统都使用,函数的前几个参数都在寄存器中传递。这就是为什么在堆栈上看不到它们:它们不会在堆栈上传递

具体来说,前几个整数或指针参数在rdi、rsi、rdx中传递,而前几个浮点参数在xmm0、xmm1和xmm2中传递。由于在xmm0中传递了一个数字,但printf试图从rsi读取一个数字,因此您将看不到您提供的数字与打印出来的数字之间的任何关联

对于未来的读者:请注意OP试图做的是。ISO 9899:2011指定应为%d传递一个int,但OP正在尝试将其与双精度after默认参数一起使用。为此,OP应改用%f。使用错误的格式说明符是未定义的行为。请不要假设观测值在您的系统上或任何地方保持不变,也不要编写此类代码。

您尝试使用%d作为浮点:

d说明符用于有符号十进制整数

f说明符用于十进制浮点

使用错误的说明符会导致

您依赖于自动变量的地址:

我试图通过查看一个窗口附近的内存来预测输出

a是一个自动变量,它的地址在每次编译代码时都会更改,所以memory-near-a也会在每次编译代码时更改

因此,查看a附近的内存也会导致未定义的行为

解决方案:


在这种情况下,您与未定义的行为无关,因此为了节省时间,请忘记它,它将使您的生活更轻松。

是的。这是一个64位系统,使用错误的格式说明符是未定义的行为。为什么要询问UB?你知道UB没有定义吗?C是如何实现的?你是说这个特定的编译器今天是如何实现的?在下一个版本中可能会有所不同。或者在不同的编译器中。或者在不同的平台上。我不认为OPs的问题是使用什么格式说明符。为什么你总是盯着错误的格式说明符?虽然在技术上没有定义行为,但由于printf的实现方式,当您传递错误的格式说明符时会发生什么,这是非常明确的。我认为这个答案对OP毫无帮助。@FUZxxl由于printf的实现方式而定义良好?唯一定义得很好的是行为是非常未定义的。您的答案还应该包括参数int和double的大小,以及默认升级为int/double@FUZxxl你的答案被删除并被否决,因为你没有提到UB。如果你这样做的话,它将被升级而不是删除。无知不是问题所在,你提出其他建议是不礼貌的。这里的评论已经解释了一切,所以没有必要访问meta。也许需要一些倾听和理解?我们已经解释过很多次了。我不会重复我和其他很多人说过的话。让我们恭敬地同意不同意。我不会说这是一种固定。我个人认为,在某个特定的时间点上看UB如何在一个特定的编译器中表现并没有什么好处。我无法帮助你解释为什么其他人投票,而不是在这里投票。我的理解是,未定义的行为是,嗯,未定义的。我仍然不明白你为什么不明确地,前面和中间,这是UB。然后,您可以继续解释这个编译器和这个ABI发生了什么。当然你需要向询问者指出这是UB。提问者是否意识到这一点还不清楚。因此,请务必在回答的顶部说明行为是未定义的,不能依赖它;但是,我们可以使用这个特定的实现/ABI作为一个示例,说明为什么行为是未定义的,以及不假设任何关于实现行为的内容可以实现哪些好处。@fuzzxl为什么拒绝?一定要记住,这个答案可能会被许多C程序员读过,他们会误解你的措辞,以为你实际上可以依靠所说的行为。以目前的形式来看,这个答案有点危险,尽管是正确的。
0x7fff5fbffb98: 1075000115
0x7fff5fbffb9c: 0
0x7fff5fbffba0: 1606417336
0x7fff5fbffba4: 32767
0x7fff5fbffba8: -1754266167
0x7fff5fbffbac: 32767
0x7fff5fbffbb0: -1754266167
0x7fff5fbffbb4: 32767