首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场

普林特
EN

Stack Overflow用户
提问于 2014-01-10 03:13:33
回答 1查看 209关注 0票数 7

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

代码语言:javascript
运行
复制
 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;
}

这被调用了数百万次,但问题是,尽管大多数时候应该是相同的,但从来没有,而且输出是非常奇怪的。

代码语言:javascript
运行
复制
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两次打印都不一样?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-01-10 03:15:56

不能使用%d打印long long。你必须使用%lld。(所以使用"\n%d %d | %lld %lld | %d %d"作为您的格式字符串。)

特别是,很明显,在"52 0\ 52 0“中,前52 0是a.rez,第2 52 0是b.rez (其中每一个都是long long,显然是(从输出来看)将两个单词推到堆栈中)。a.tonumb.tonum根本没有打印。

为了理解为什么会发生这种情况,让我解释一下乔纳森和我想说的话。当您调用像printf这样的变量函数(声明为类似于printf(const char *format, ...)的函数)时,编译器无法在编译时验证...的正确参数类型。因此,在这种情况下,有一个决定在堆栈上推入什么的过程,大致可以概括为:如果它是int或可升级到int,则它被作为int推送;如果它是double或可提升到double,则它被推送为double;否则,它按原样推送。

在实现像printf这样的变量函数时,您需要某种方式来访问...项。这样做的方法是使用va_list,这是在<stdarg.h>中声明的。下面是一些伪代码,它展示了如何使用它:

代码语言:javascript
运行
复制
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.tonumb.tonum的值。

然而,如果您正确地使用了%lld,它就会使用va_arg(ap, long long),并且将正确地读取整个64位的数量。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21035568

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档