阅读 ‧ 电子书库 整数溢出
如果整数太大,超出了整数类型的范围会怎么样?下面分别将有符号类型和无符号类型整数设置为最大允许值加略大一些的值,看看结果是什么(printf()函数使用%u说明符显示unsigned int类型的值)。
阅读 ‧ 电子书库
下面是我们使用的系统的结果:
阅读 ‧ 电子书库
无符号整数j像一个汽车里程指示表,当达到最大值时,它将溢出到起始点。整数i也是同样。它们的主要区别是unsigned int变量j的起始点是0(正像里程指示表那样),而int变量i的起始点则是-2147483648。注意到当i超过(溢出)它的最大值时,系统并没有给出提示,所以编程时您必须自己处理这个问题。
这里描述的现象由C中关于无符号类型的规则所操纵,C标准没有定义有符号类型的溢出规则。这里的现象是比较有代表性的,但你也可能遇到不同的情况。

三、long常量和long long常量

通常,在程序代码中使用2345这样的数字时,它以int类型存储。当使用1000000这样的数字int类型不能表示时,编译器会视其为long int类型(假定这种类型可以表示该数字)。如果数字大于long类型的最大值,C会视其为unsigned long类型。如果仍然不够,C会视其为long long类型或者unsigned long long类型(如果有这些类型的话)。

八进制和十六进制常量通常被视为int类型。如果值过于大,编译器会试用unsigned int,如果不够大,编译器会依次试用long、unsigned long、long long和unsigned long long类型。

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

有时候您也许会希望编译器用long类型来存储一个较小的整数。例如,在编程中涉及到显式使用IBM PC上的内存地址时,就会产生这样的需求。一些标准的C函数也需要long类型的值。如果希望把一个较小的常量作为long类型对待,可以使用1(小写的L)或L后缀。使用L后缀是更好的选择,因为1同数字1很相近。这样,在int类型为16位、long类型为32位的系统中,会把整数7作为16位数存储,而把整数7L作为32位数存储。1和L后缀对八进制和十六进制数同样适用,比如020L和0x10L。

与之类似,在支持long long类型的系统中,可以使用11或LL后缀标识long long类型值,比如3LL。u或U后缀用于标识unsigned long long类型值,比如5ull、10LLU、6LLU和9Ull。

四、打印short、long、long long和unsigned类型数

要打印unsigned int数字,可以使用%u符号。打印long数值,可以使用%ld格式说明符。如果系统的int和long类型具有同样的长度,使用%d就可以打印long数值,但是这会给程序移植到其他系统(这两种数据类型的长度不一样的系统)带来麻烦,所以建议使用%ld打印long数值。在x和o符号前也可以使用1前缀,因此%lx表示以十六进制格式打印长整数,%lo表示以八进制格式打印长整数。请注意,尽管在C中常量后缀可以使用大写和小写,但格式说明符只能使用小写字母。

C还有其他几种printf()格式。首先,可以对short类型使用h前缀,因此%hd表示以十进制显示short整数,%ho表示以八进制显示short整数。h和l前缀都可以同u结合使用以表示无符号类型。比如,%lu表示打印unsigned long类型。程序清单3.4给出了一个例子。支持long long类型的系统使用%11d和%llu分别表示有符号类型和无符号类型。第4章将详细介绍格式说明符。

程序清单3.4 print2.c程序

阅读 ‧ 电子书库

下面是在某系统上的执行结果:

阅读 ‧ 电子书库

这个例子表明如果使用了不正确的说明符,会造成意想不到的后果。首先,对无符号变量un使用%d说明符会导致显示负值!这是由于在程序运行的系统中,无符号数3000000000和有符号数-129496296在内存中的表示方法是一样的(详见第15章)。所以,如果告诉printf()函数该数值是无符号的,它将打印某个值;而如果告诉printf()函数该数值是有符号的,它将打印另外一个值。在数值大于有符号类型最大值的时候会发生这种情况。对于小一些的正数(比如96),有符号和无符号类型的存储和显示都是相同的。

其次,不论使用%hd还是%d,short类型变量end的显示结果相同。这是因为在传递函数参数时C自动将short类型的值转换为int类型。这会在您的脑子里引起两个疑问:为什么要进行这样的转换?h修饰符的用处是什么?第一个问题的答案是:int类型被认为是计算机处理起来最方便有效的整数类型,所以在short类型和int类型长度不同的系统中,使用int类型值进行参数传递的速度更快;第二个问题的答案是:可以使用h修饰符显示一个较长的整数被截为short类型值时的样子。输出的第三行就演示了这一点。把值65537按照二进制格式写为一个32位的数字时,它应该是00000000000000010000000000000001。在printf()中使用%hd说明符将使它只显示后16位,即显示值1。与此类似,最后一行输出先显示了verybig变量的完整值,然后通过使用%ld说明符显示了存储在它的后32位中的值。

前面您已经认识到应该确保说明符的数目与要显示的值的数目相匹配。这里说明了还必须根据要显示的值的类型来选用正确的说明符。