2009-09-06 63 views
10

采取以下:C:打印大的数字

#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将打印正确的数字。

这是什么原因?

回答

25

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

而且我可以告诉大家,不,编译器可能足够聪明,在printf()格式字符串从"%llu“看着办吧。这是一个不同的抽象级别,编译器是负责语言的语法,printf()语义是不是语法的一部分,它是一个运行时库函数(没有从自己的职能不同的真正不同之处在于它包含在标准)。

考虑下面的代码为32位int和64位无符号long 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×2 + 1. 2参数正被无意中包含在ULL值中。

第二,你实际上推64位1值和一个多余的32位整数2,这被忽略。

请注意,您的格式字符串和实际参数之间的“步调不一致”是一个坏主意。喜欢的东西:

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

可能崩溃,因为32位"hello"指针将由%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

,但我认为编译器足够聪明弄清楚%U在printf格式规范,尝试printf(“%d%u”,〜0,〜0)..都将按预期打印值。 – sud03r 2009-09-06 19:18:51

+0

否 - 这些数据类型的大小相同 - 它是printf() %d与'a'。 – paxdiablo 2009-09-06 22:43:26

+0

Pax:这也很好,字符文字是整数常量。 – caf 2009-09-07 01:26:58

3

285212672是一个int的值。 printf预计unsigned long long,你通过它int。因此,它会从堆栈中获取更多字节,而不是传递实际值并打印垃圾。在将它传递给函数之前,如果将它放入unsigned long long变量中,它将在分配行中升级为unsigned long long,并将该值传递给printf,该值可正确运行。

0

数据类型只是一种解释内存位置内容的方法。
在第一种情况下,常量值作为int存储在只读存储单元中,printf尝试将此地址解释为8个字节的位置,因为它指示所存储的值在很长的过程中打印出垃圾值。
在第二种情况下,printf尝试将长整型值解释为8个字节,并打印出预期内容。

5

值得指出的是,一些编译器会给出这种情况下的有用的警告 - 例如,这是海湾合作委员会说,关于你的代码:

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

另一个不忽略编译*警告*的理由。 – reuben 2009-09-07 02:30:23