【问题标题】:Printf of an object with integer members具有整数成员的对象的 Printf
【发布时间】:2019-07-09 17:30:24
【问题描述】:

我有这些奇怪的行为。 如果我使用下面的代码

class Simple
{
public:
    Simple()
    {
        m = 1;
        mm = 2;
        mmm = 3;
    }

    ~Simple()
    {
    }

private:
    int mmm;
    int mm;
    int m;
};

int main(int argc, char** argv)
{
    Simple sim;

    printf("%d\n", sim);
}

由于 printf 的结果,我有数字“3”。 如果我首先放入声明,例如,变量“mm”而不是“mmm”,则 printf 的结果是数字“2”。 如果我在声明中首先放入变量“m”,则行为相同,printf 给我“1”。 似乎 printf 可以打印声明的第一个 int 变量。怎么可能?

【问题讨论】:

  • 俗话说,未定义的行为是未定义的。
  • 请记住,当人们编写“未定义的行为”时,这意味着编程语言没有您正在研究的表达式的标准行为。这意味着每个编译器供应商都可以决定如何处理它。
  • @nicomp 编译器不必决定如何处理它。他们可以简单地假设 UB 永远不会发生,因为他们不必关心有 UB 时会发生什么。
  • 未定义的行为可能发生任何事情,因此您必须习惯它。 C++ 和 C 旨在提高效率,因此在许多情况下,假设您知道自己在做什么,并且没有为您内置错误检查。当您导致未定义的行为时,不能保证您会收到错误,并且您的程序可能看起来工作正常。
  • 下一次,使用std::cout,从而学习如何为您的Simple 类正确实现operator <<

标签: c++ printf


【解决方案1】:

printf 是一个可变参数函数,这意味着它不知道如何检查第二个和后续参数的类型。因此,在一个典型的实现中,它相信你给它的参数是%d所指示的正确类型,即int。您的 sim 对象在内存中是三个 ints 打包在一起。 printf,给定%d,尝试读取int 并获取您在sim 中声明的第一个int 变量。

请注意,这是未定义的行为,您不应依赖它。

【讨论】:

  • 这是有道理的。事实上,如果我写 printf("%d%d%d\n", sim);,我有 "321"。
  • @VFG • 只是更多未定义的行为,可能因编译器而异,或者取决于启用的编译器优化。
  • @VFG 无论如何这不是保证,只需在你的类上定义运算符
  • @VFG 不。您现在编写的代码不能保证做任何明确的事情。如果您在不同的编译器上尝试它或使用不同的编译器选项,它甚至可能使程序崩溃。
  • @JoshWilson "printf 是一个可变参数函数,这意味着它不知道如何检查第二个和后续参数的类型" - 许多现代编译器为如果使用编译时字符串文字,则在编译时使用 printf 样式函数,以确保根据格式字符串传入有效参数。
猜你喜欢
  • 1970-01-01
  • 2017-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-07
相关资源
最近更新 更多