C:打印大号

时间:2009-09-06 14:42:58

标签: c printf

采取以下措施:

#include <stdio.h>

main() {
    unsigned long long verybig = 285212672;

    printf("Without variable : %llu\n", 285212672);
    printf("With variable    : %llu", verybig);
}

这是上述程序的输出:

Without variable : 18035667472744448
With variable    : 285212672

从上面可以看出,当printf作为常量传递时,它会打印一些大小不正确的数字,但是当该值首次存储在变量中时,printf会打印出来正确的号码。

这背后的原因是什么?

4 个答案:

答案 0 :(得分:25)

尝试285212672ULL;如果你在没有后缀的情况下编写它,你会发现编译器将它视为常规整数。它在变量中工作的原因是因为整数在赋值中被强制转换为unsigned long long,因此传递给printf()的值是正确的类型。

在您提出问题之前,不,编译器可能 不够聪明,无法从"%llu格式字符串中的printf()中找出它。这是一个不同的编译器负责语言语法,printf()语义不是语法的一部分,它是一个运行时库函数(与你自己的函数没什么不同,除了它包含它在标准中)。

对于32位int和64位无符号长long系统,请考虑以下代码:

#include <stdio.h>

int main (void) {
    printf ("%llu\n",1,2);
    printf ("%llu\n",1ULL,2);
    return 0;
}

输出:

8589934593
1

在第一种情况下,两个32位整数1和2被压入堆栈,printf()将其解释为单个64位ULL值,2 x 2 32 + 1. 2参数无意中包含在ULL值中。

在第二种情况下,实际上是推送64位1值和多余的32位整数2,这将被忽略。

请注意,格式字符串与实际参数之间的“不合时宜”是一个坏主意。类似的东西:

printf ("%llu %s %d\n", 0, "hello", 0);

可能会崩溃,因为"hello"将使用32位%llu指针,而%s将尝试取消引用最终的0参数。下面的“图片”说明了这一点(我们假设单元格是32位,“hello”字符串存储在0xbf000000。

What you pass     Stack frames     What printf() uses
                 +------------+
0                | 0          | \
                 +------------+  > 64-bit value for %llu.
"hello"          | 0xbf000000 | /
                 +------------+
0                | 0          |    value for %s (likely core dump here).
                 +------------+
                 | ?          |    value for %d (could be anything).
                 +------------+

答案 1 :(得分:5)

值得指出的是,有些编译器会对此案例发出有用的警告 - 例如,这就是GCC对您的代码所说的内容:

x.c: In function ‘main’:
x.c:6: warning: format ‘%llu’ expects type ‘long long unsigned int’, but argument 2 has type ‘int’

答案 2 :(得分:3)

285212672int值。 printf需要unsigned long long,并且您将int传递给unsigned long long。因此,它会从堆栈中获取更多的字节,而不是传递实际值并打印垃圾。如果在将unsigned long long变量传递给函数之前将其放在printf变量中,它将在分配行中提升为{{1}},并将该值传递给{{1}},该值可正常工作。< / p>

答案 3 :(得分:0)

数据类型只是解释内存位置内容的一种方式 在第一种情况下,常量值作为int存储在只读存储器位置中,printf尝试将该地址解释为8字节位置,因为它指示存储的值在很长的时间内打印出垃圾值。 /> 在第二种情况下,printf尝试将长long值解释为8个字节,并打印出预期的值。