- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我的源代码中有很多代码,但主要问题是连续两行。
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
因为一些其他原因在这段代码中没有解释
为什么 b.tonum
两次打印的不一样?
最佳答案
您不能使用 %d
打印 long long
.你必须使用 %lld
. (因此请使用 "\n%d %d | %lld %lld | %d %d"
作为您的格式字符串。)
特别是,很明显在“52 0 | 52 0”中,第一个 52 0 是 a.rez
, 第二个 52 0 是 b.rez
(其中每一个都是 long long
,显然(从输出判断)将两个词插入堆栈)。 a.tonum
和 b.tonum
根本不打印。
要了解为什么会发生这种情况,让我解释一下乔纳森和我想说的话。当您调用像 printf
这样的可变参数函数时(它被声明为类似 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
,并且您必须指定要选择的类型。选择正确的类型取决于您。如果类型不正确,就会出现类型双关的情况,在大多数情况下会出现未定义的行为(这意味着程序可以做任何它喜欢做的事情,包括崩溃或更糟的情况)。
在您的特定计算机中,当您通过 long long
时似乎,它将一个 64 位的数字压入堆栈,但因为您使用了 %d
格式说明符,它使用了 va_arg(ap, int)
版本,它只抓取了一个 32 位的数量。这意味着 64 位字的另一半仍未读取,即后续的 %d
。然后继续阅读。这就是为什么当格式字符串完成时,它从未处理 a.tonum
的值。和 b.tonum
你通过了。
鉴于,您是否正确使用了%lld
? , 它会使用 va_arg(ap, long long)
, 并且会正确读取整个 64 位数量。
关于c++ - Printf 疯了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21035568/
我是一名优秀的程序员,十分优秀!