程序员人生 网站导航

C语言笔记之数据类型(一)

栏目:php教程时间:2015-06-04 08:09:46

在《计算机眼里的数字》这篇文章中,我曾提到,字节是计算机最小的可寻址的单位,地址对应的是1个个字节,而不是字节的每一个位。这样编址的缘由很简单――单个的位所能表示的信息量太少了,只有两种状态0和1,只有把足够多的位组合起来才能表示足够丰富的信息。那末为何1定要是8呢?由于大家都这么做。。。好吧,肯定1定的历史缘由,我就不深究了。

但是,即便是8个位组成的字节,其所能表示的信息量依然是有限的,由于最多只有256中状态组合,如果用每种状态对应0~255之间的数字的话,那末就没法表示256这个数。这时候候只好用两个字节来表示大于255的数。一样的道理,当数字大到超过两个字节所能表示的数的极限后,就用4个字节。。。是的,你也发现了,字节数目总是翻倍增长,为何不用3个字节呢?乃至,为啥不用1.5个字节呢?对前者,是由于斟酌到对齐的缘由,这其中有太多东西要说,我就不展开了;而后者,前面其实说到了,由于没有位的编址,没法深入到字节内部把数据揪出来。。所以,存储肯定会有1定的浪费,在所难免。


上面罗嗦了那末多,其实只是为了引出本文的猪脚――C语言数据类型,为何C语言要分那末多类型呢?由于对不同大小的数,所需要的存储空间大小不同。如果都用4个字节存储,那末肯定不用分数据类型,但是好浪费哦~所以,本着节省内存的斟酌,数据类型就诞生了。C的数据类型分为基本数据类型和复合数据类型,后者只是前者的某种组合。基本数据类型依照其在计算机中的存储方式又分为整数类型和浮点数类型。


1、整数类型

整数类型包括char、short、int、long、long long,它们没有小数部份。char虽然是字符类型,但是由于存储的是ASCII码,本质上也是按整数存储的,所以归为这1类。不同的整数类型具有不同的字节数,从而所占用的存储空间不同。但是,这1点是不肯定的,准确的字节数依赖于具体的机器和编译器――机器不但分品牌,还有32位和64位之分。下面的表格给出不同类型所占有的典型的字节数(来源《深入理解计算机系统》):

类型 32位机器 64位机器
char 1 1
short 2 2
int  4 4
long 4 8
long long 8 8
char * 4 8
float 4 4
double 8 8


注意,上表只是典型值,以32位为例:在有的机器上,short和int都是2个字节,long是4个字节;而有的机器上,short是2个字节,而int和long是4个字节。C语言仅仅规定:short <= int <= long,然后char是1个字节。不过,对大部份机器,上表够用了。要查看自己机器上每种类型所占的字节数,请用sizeof(类型)来查看。

对整数类型,C还用了signed和unsigned来修饰它们,以取得有符号数和无符号数,缺省时,认为是有符号数。正如在《计算机眼里的数字》中提到的那样,有符号数和无符号数的2进制表示多是1样的,区分仅仅是解读方式。

有了各种类型以后(即字节数肯定以后),就能够规定它们所表示的数的范围。下表是32位机器各种类型的典型取值范围:

  signed unsigned
char ⑴28 ~ 127 0 ~ 255
short ⑶2768 ~ 32767 0 ~ 65535
int  ⑵147483648 ~ 2147483647 0 ~ 4294967295
long ⑵147483648 ~ 2147483647 0 ~ 4294967295
long long ⑼223372036854775808 ~ 9223372036854775807 0 ~ 18446744073709551615


这些界限值可以通过包括limits.h头文件加以查看,比如对int值的各种范围,可以通过打印INT_MAX  INT_MIN  

UINT_MAX UINT_MIN 来查看。


我们用几个例子来看1下相同类型之间signed和unsigned的转换。

1、将signed强迫转换成unsigned:

<span style="font-size:18px;">#include <stdio.h> int main(void) { int a = ⑴; unsigned int b = (unsigned int)a; printf("a = %d, b = %d ", a, b); printf("a = %u, b = %d ", a, b); printf("a = %d, b = %u ", a, b); printf("a = %#x, b = %#x ", a, b); return 0; } </span>

运行结果以下:

<span style="font-size:18px;">a = ⑴, b = ⑴ a = 4294967295, b = ⑴ a = ⑴, b = 4294967295 a = 0xffffffff, b = 0xffffffff</span>

可以明显的看出,将1个负数强迫转换为无符号数,并没有改变其位模式(2进制表示),它依然依照原来的样子存储,第4行的结果证明了这1点;而前3行的结果表明,即便不做signed到unsigned的强迫类型转换,只需要在打印时改变1下输出格式,就可以到达一样的效果。(这里我开始怀疑把1个变量声明为unsigned有啥意义?)


而将1个有符号的正数转换为同类型的无符号数又如何呢?

2、将unsigned强迫转换成signed:

<span style="font-size:18px;">#include <stdio.h> int main(void) { unsigned short a = 32767; short b = (short)a; printf("a = %u, b = %u ", a, b); printf("a = %u, b = %d ", a, b); printf("a = %d, b = %u ", a, b); printf("a = %#x, b = %#x ", a, b); return 0; } </span>
结果以下:

<span style="font-size:18px;">a = 32767, b = 32767 a = 32767, b = 32767 a = 32767, b = 32767 a = 0x7fff, b = 0x7fff </span>
可以看出,当1个非负数处于0~TMax(TMax代表某1类型有符号数的最大值)的范围时,不管把它的2进制表示解读成signed还是unsigned,结果都是1样的。这是由于,处于这部份范围内的数,转换成2进制时,最高为都为0,如果按signed解读,它是1个正数,数字部份就是7fff,;而按unsigned解读,07fff == 7fff,结果总是1样的。

那如果正数的范围超过了TMax呢?

<span style="font-size:18px;">#include <stdio.h> int main(void) { unsigned int a = 2147483648u; int b = (int)a; printf("a = %u, b = %d ", a, b); printf("a = %d, b = %u ", a, b); printf("a = %#x, b = %#x ", a, b); return 0; } </span>

结果:

<span style="font-size:18px;">a = 2147483648, b = ⑵147483648 a = ⑵147483648, b = 2147483648 a = 0x80000000, b = 0x80000000</span>
可以看到,底层的2进制表示依然是1致的,只是解读方式产生了变化:由于最高位是1,所以解读成signed时,是1个负数;解读成unsigned依然是正数,结果不同。

注意:由于变量分为signed和unsigned,对应的常量也要分为signed和unsigned;类型前没有修饰时,默许为signed,对应的,1个常量数字默许为signed,即有符号数。如果希望1个常量数字被当做无符号数,就要在其末尾添加字母'u'或‘U’。

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐