C语言基础03—不匹配的整数转换

当类型不匹配的时候,往往计算机输出的值和我们的预估值不一样。

下面我们以计算机存储数据的方面去剖析为什么出来的结果和预估的值不一样。

 我们看如下代码:

#include <stdio.h>
#define PAGES 336
#define WORDS 65618
int main(void)
{
    short num = PAGES;
    short mnum = -PAGES;

    printf("num as short and unsigned short: %hd %hu\n", num, num);
    printf("-num as short and unsigned short: %hd %hu\n", mnum, mnum);
    printf("num as int and char: %d %c\n", num, num);
    printf("WORDS as int, short, and char: %d %hd %c\n", WORDS, WORDS, WORDS);

    return 0;
}

在gcc上的运行结果为:

从第一行看到,%hd 和%hu产生336作为变量num的输出,毫无疑问。

然而,mnum的%u(无符号)版本的输出结果则为65200,而非所期望的336。

这是由于有符号short int值在我们的参考系统中的表示方式所造成的。

首先,它们的大小为2字节。其次,该系统使用一种被称为2的补码(two's complement)的方法来表示有符号整数。

在这种方式中,数字0~32767代表他们本身,而数字32768~65535则代表负数,65535代表-1、65534代表-2,以此类推。

因此,-336由65536-336,也即65200来表示。所以当被解释成一个有符号整数时,65200代表-336;

而被解释成无符号整数时,65200则代表65200。

一定要谨慎!一个数字可以被解释成两个不同的值。

不是所有系统都用该方法来表示负整数。虽然如此,还是有一个准则:不要期望%u转换能把数字和符号分开。

第三行显示如果你试图把一个大于255的值转换成字符,将会发生什么事情?

在该系统上,一个short int占2个字节,一个char占用1个字节。

当printf()使用%c打印336时,它只查看用于存放336的两个字节中的一个字。

这种截断相当于用256除一个整数,并取其余数。如下图所示:

在这种情况下余数为80,也即使字符p的ASCII码值。

更技术一些可以说,该数字被解释成“以256为模”,意即使用数字被256除的余数。

最后试着打印一个比系统允许的最大的short int(32767)大的整数(65618)。

这次计算机又进行了模运算。我们的系统根据数字65618的大小,将它存储为4个字节的整数值。

当我们使用%hd说明符打印它时,printf()只使用最后2个字节。这相当于使用被65536除后得到的余数。在这里,余数是82。

鉴于负数的存储方法,在32767和65536之间的余数会被打印成负数。

整数大小不同的系统将会做出相同的动作,但是会产生不同的数值。

当混淆了整数和浮点类型时,结果更是千奇百怪。例如:

 

#include <stdio.h>
int main(void)
{
    float n1 = 3.0;
    double n2 = 3.0;
    long n3 = 2000000000;
    long n4 = 1234567890;

    printf("%.1e %.1e %.1e %.1e\n", n1, n2, n3, n4);
    printf("%ld %ld\n", n3, n4);
    printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);

    return 0;
}

 

目前一般的情况是,long long类型为64位——8字节,long类型为32位——4字节,short类型为16位——2字节,

int类型为16位或32位(依机器的自然字大小而定)。

 

posted @ 2017-07-12 17:18  Liu_Jing  Views(476)  Comments(0)    收藏  举报