Printf疯狂了

时间:2014-01-10 03:13:33

标签: c++ struct operator-overloading

我的源码中有很多代码,但主要问题是连续两行。

 struct step
 {
     int left,tonum;
     long long int rez;
 };

inline bool operator==(const step& a, const step& b)
{
    printf("\n%d",b.tonum);
    printf("\n%d %d | %d %d | %d %d",a.left, b.left, a.rez, b.rez, a.tonum, b.tonum);
    return a.left==b.left && a.rez==b.rez && a.tonum==b.tonum;
}

这被称为相当几百万次,但问题是虽然它在大多数情况下应该是相同的,但它永远不会,并且输出确实非常奇怪。

2
7989 7989 | 53 0 | 53 0
1
8989 7989 | 52 0 | 53 0
2
8989 8989 | 52 0 | 52 0
1
7899 8989 | 51 0 | 52 0

b.tonum不仅应该是相同的,而且由于其他一些原因而不应该== a.tonum

为什么不{not} b.tonum两次打印相同?

1 个答案:

答案 0 :(得分:10)

您无法使用%d打印long long。您必须使用%lld。 (因此请使用"\n%d %d | %lld %lld | %d %d"作为格式字符串。)

特别是,在&#34; 52 0 |中显而易见52 0&#34;,第一个52 0是a.rez,第二个52 0是b.rez(每个都是long long,显然是(从输出判断)推动两个字到堆栈)。 <{1}}和a.tonum根本不打印。


要理解为什么会发生这种情况,让我解释一下Jonathan和我想说的话。当您调用类似b.tonum的变量函数(声明为类似printf的函数)时,编译器具有 no 方式来验证printf(const char *format, ...)的正确参数类型在编译时。所以有一个程序来决定在这种情况下推送堆栈的内容,大致可以概括为:如果它是...或可推广到int ,它被推送为int;如果它是int或可推广到double,它会被推送为double;否则,它会按原样推送

在实现类似double的可变参数函数时,您需要一些方法来访问printf项。这样做的方法是使用在...中声明的va_list。这是一些伪代码,显示了它是如何使用的:

<stdarg.h>

请注意,每次要选择int printf(const char *format, ...) { va_list ap; va_start(ap, format); while (/* we find the next format marker */) { if (/* %d, %i, %c */) { int val = va_arg(ap, int); /* print out val as decimal or (for %c) char */ } else if (/* %u, %x, %X, %o */) { unsigned int val = va_arg(ap, unsigned int); /* print out val as decimal, hex, or octal */ } else if (/* %ld, %li */) { long val = va_arg(ap, long); /* print out val as decimal */ } else if (/* %lu, %lx, %lX, %lo */) { unsigned long val = va_arg(ap, unsigned long); /* print out val as decimal, hex, or octal */ } else if (/* %lld, %lli */) { long long val = va_arg(ap, long long); /* print out val as decimal */ } else if (/* %llu, %llx, %llX, %llo */) { unsigned long long val = va_arg(ap, unsigned long long); /* print out val as decimal, hex, or octal */ } else if (/* %s */) { const char *val = va_arg(ap, const char *); /* print out val as null-terminated string */ } /* other types */ } va_end(ap); return /* ... */; } 参数时,都要使用...进行操作,并且必须指定要选择的类型。您可以选择正确的类型。如果类型不正确,则会出现类型错误,在大多数情况下会出现未定义的行为(意味着程序可以执行任何喜欢的操作,包括崩溃或更糟)。

在您的特定计算机中,似乎当您传递va_arg时,它将64位数量推送到堆栈,但由于您使用了long long格式说明符,因此使用了{{ 1}}版本,只获取32位数量。这意味着64位字的另一半仍然未读,随后%d继续阅读。这就是为什么在格式字符串完成时,它永远不会处理您传递的va_arg(ap, int)%d的值。

然而,如果您正确使用a.tonum,它将使用b.tonum,并且可以正确读取整个64位数量。