【问题标题】:How does printf() 'mysteriously' know what I intended to print?printf() 如何“神秘地”知道我打算打印什么?
【发布时间】:2013-09-17 04:25:34
【问题描述】:

我忘记将附带的变量添加到 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");

有问题的代码是最后一行三元表达式的最后一个“else”。我已经运行了几十次,它似乎总是在输出中打印出正确的参数。

: printf("\n'%d' was NOT found\n\n");

如何每次仍然有效?

【问题讨论】:

  • 未定义的行为?

标签: c printf


【解决方案1】:

它可能看起来有效,但不要依赖这个。

这可能是因为您最近的函数调用,

successful = search(list, data);

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


在这里提一下可能会很有用,如果您忽略在声明单个局部变量的函数中包含 return 语句,有时会发生类似的 serendipity

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

    // <-- no return statement!
}

有时会返回局部变量val,可能是由于同一种堆栈重用。但这也是未定义的行为,即使它碰巧起作用。


这两种情况的寓意是启用更多的编译器警告。编译器可以诊断此类问题,甚至检查格式字符串是否与传递给 prinf-family 函数的变量类型匹配。

【讨论】:

    【解决方案2】:

    哎呀!那是“未定义的行为”。

    printf("\n'%d' was NOT found\n\n"); // undefined behavior
    

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

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

    successful = search(list, data);
    //                        ^^^^ places "data" on stack as second argument
    

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

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

    【讨论】:

    • 我只是在等待一个 gcc 扩展,它可以根据未定义的行为格式化开发人员的硬盘。
    • @Thomas C-x M-C M-nasaldemons 就够了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 1970-01-01
    • 2019-12-30
    • 2014-12-14
    • 1970-01-01
    • 2021-08-21
    相关资源
    最近更新 更多