【问题标题】:Printf with no arguments explanation不带参数的 printf 解释
【发布时间】:2014-12-26 18:27:40
【问题描述】:

我知道如果 printf 没有给出任何参数,它会输出一个意外的值。

例子:

#include <stdio.h>

int main() {
    int test = 4 * 4

    printf("The answer is: %d\n");
    return 0;
}

这会返回一个随机数。在使用不同的格式(如 %p、%x 等)后,它不会打印 16(因为我没有将变量添加到参数部分)我想知道的是,这些值在哪里被取从?它是堆栈的顶部吗?每次编译都不是新的值,这很奇怪,就像一个固定的值。

【问题讨论】:

  • 这是未定义的行为。它似乎固定的事实是一个快乐的意外。它可能来自堆栈,也可能来自寄存器......你不知道,不应该关心或指望它。
  • 1.使用printf("The answer is: %d\n"),您正在传递 one 参数。 2. 如果该参数指向一个不包含% 字符的空终止字符串,那么printf 将输出一个符合预期的值。

标签: c printf


【解决方案1】:
printf("The answer is: %d\n");

调用未定义的行为。 C 要求转换说明符具有关联的参数。虽然这是未定义的行为并且任何事情都可能发生,但在大多数系统上,您最终都会转储堆栈。这是format string attacks中使用的技巧。

【讨论】:

    【解决方案2】:

    它叫undefined behavior,它是可怕的(见this answer)。

    如果您需要解释,则需要深入了解具体实施细节。因此,请研究生成的源代码(例如,使用gcc -Wall -Wextra -fverbose-asm + 您的优化标志进行编译,然后查看生成的.s 汇编文件)和系统的ABI

    【讨论】:

    • 啊哈,我喜欢你提供的答案。好吧,那我去检查一下。
    【解决方案3】:

    printf 函数将在堆栈上查找参数,即使您没有提供参数。如果找不到整数参数,则将使用那里的任何内容。大多数时候,你会得到无意义的数据。选择的数据取决于编译器的设置。在某些编译器上,您甚至可能得到 16。

    例如:

    int printf(char*, int d){...}
    

    这就是 printf 的工作方式(不是真的,只是一个例子)。如果 d 为 null 或为空,它不会返回错误,它只是在堆栈中查找应该显示的参数。

    【讨论】:

    • 在某些 ABI 上,可变参数函数的调用方式与固定参数函数不同。
    【解决方案4】:

    Printf 是一个可变参数函数。大多数编译器将参数压入堆栈,然后调用函数,但是,根据机器、操作系统、调用约定、参数数量等,还有其他值压入堆栈,这在您的函数中可能是常量。

    Printf 读取这块内存并返回它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-12
      • 2011-05-25
      相关资源
      最近更新 更多