来源:www.cncfan.com | 2006-4-28 | (有6229人读过)
kingwei 2005.3.10
实验环境: Dev-C++ 4.9.6.0 (gcc/mingw32), 使用-Wall编译选项
#include <stdio.h>
int main() { signed long long int v_signed_long_long_int; unsigned long long int v_unsigned_long_long_int; /* PART1:USE %I64d AND %I64u */ /* [-2^63, 2^63-1] ==> [-9223372036854775808, 9223372036854775807] */ scanf("%I64d", &v_signed_long_long_int); printf("%I64d\n", v_signed_long_long_int);
/* [0, 2^64-1] ==> [0, 18446744073709551615] */ scanf("%I64u", &v_unsigned_long_long_int); printf("%I64u\n", v_unsigned_long_long_int);
/* PART2:USE %lld AND %llu */ /* [-2^63, 2^63-1] ==> [-9223372036854775808, 9223372036854775807] */ scanf("%lld", &v_signed_long_long_int); printf("%lld\n", v_signed_long_long_int);
/* [0, 2^64-1] ==> [0, 18446744073709551615] */ scanf("%llu", &v_unsigned_long_long_int); printf("%llu\n", v_unsigned_long_long_int); return 0; }
这个程序在Dev-C++下编译会有一系列Warning:
D:\Dev-C++下关于long long类型的实验\llint_format.cpp [Warning] In function `int main()': 14 D:\Dev-C++下关于long long类型的实验\llint_format.cpp [Warning] unknown conversion type character `I' in format 14 D:\Dev-C++下关于long long类型的实验\llint_format.cpp [Warning] too many arguments for format 15 D:\Dev-C++下关于long long类型的实验\llint_format.cpp [Warning] unknown conversion type character `I' in format 15 D:\Dev-C++下关于long long类型的实验\llint_format.cpp [Warning] too many arguments for format 18 D:\Dev-C++下关于long long类型的实验\llint_format.cpp [Warning] unknown conversion type character `I' in format 18 D:\Dev-C++下关于long long类型的实验\llint_format.cpp [Warning] too many arguments for format 19 D:\Dev-C++下关于long long类型的实验\llint_format.cpp [Warning] unknown conversion type character `I' in format 19 D:\Dev-C++下关于long long类型的实验\llint_format.cpp [Warning] too many arguments for format
可以看到,Warning都是因为PART1中使用了格式符%I,而产生的。PART2则一切正常,编译器没有给出任何警告信息。
但是——请看测试结果:
----- test case #1: 下界 -----
-9223372036854775808 0 -9223372036854775808 0
output:
-9223372036854775808 0 0 0
----- test case #2: 上界 -----
9223372036854775807 18446744073709551615 9223372036854775807 18446744073709551615
output:
9223372036854775807 18446744073709551615 -1 4294967295
----- test case #3: 下溢 -----
-9223372036854775809 -1 -9223372036854775809 -1
output:
9223372036854775807 18446744073709551615 -1 4294967295
----- test case #4: 上溢 -----
9223372036854775808 18446744073709551616 9223372036854775808 18446744073709551616
output:
-9223372036854775808 0 0 0
结果恰恰相反,PART1的工作完全正常,PART2却产生了问题. 为什么呢?我是这样猜想的:
"%lld"和"%llu"是linux下gcc/g++用于long long int类型(64 bits)输入输出的格式符。
而"%I64d"和"%I64u"则是Microsoft VC++库里用于输入输出__int64类型的格式说明。
问题就出在:Dev-C++使用的编译器是Mingw32,Mingw32是x86-win32 gcc子项目之一,编译器核心还是linux下的gcc。
进行函数参数类型检查的是在编译阶段,gcc编译器对这段代码进行检查,显然它不认得"%I64d", 所以给出了警告“unknown conversion type character `I' in format”,它不认为这是一个格式说明符。 接着,gcc发现整个格式字符串里没有合法的说明符,但传给printf/scanf的除了格式字符串,还有数据参数, 于是它又给出了第二个警告“too many arguments for format”。
对于"%lld"和"%llu",gcc理所当然地接受了。悲剧就此埋下了伏笔。
Mingw32在编译期间使用gcc的规则检查语法,在连接和运行时使用的却是Microsoft库。 这个库里的printf和scanf函数当然不认识linux gcc下"%lld"和"%llu",对"%I64d"和"%I64u",它则是乐意接受的。
——于是就出现了上面的结果。
|