1. 整型数据类型
C语言里面的整数数据类型
类型名称 |
C语言中的关键字 |
注释 |
字符型 |
char |
表示一个很小的整数 |
短整型 |
short |
表示一个不怎么大的整数 |
整型 |
int |
生活中一般的整数都可以表示 |
长整型 |
long |
较大的整数 |
加长整型 |
long long |
非常大的整数 |
一个整数而已,为什么会需要定义这么多不同的类型出来呢?
计算机通过晶体管的开关状态来记录数据。它们通常8个编为一组,我们称之为字节。而晶体管有开关两种状态,一个字节有8个晶体管,因此一个字节可以拥有2的八次方个不同的状态。让每一种状态对应一个数值,这样一个字节可以表示256个不同数值。
晶体管状态 |
二进制数值 |
十进制数值 |
关关关关关关关关 |
00000000 |
0 |
关关关关关关关开 |
00000001 |
1 |
关关关关关关开关 |
00000010 |
2 |
关关关关关关开开 |
00000011 |
3 |
… |
… |
… |
开关开关开关开关 |
10101010 |
170 |
开开开开开开开开 |
11111111 |
255 |
要表示更大的数据范围就需要更多晶体管。要知道在发明C语言的年代,计算机存储资源是非常珍贵而稀缺的。如果只想表达0到100以内的数值,那么一个字节就足够了,何必用两个字节来存储?
而如今,即使存储资源已经较为丰富了,但是大部分的强类型语言,都延续了这个传统。它们均提供了丰富的类型以供选用。而程序员在编写代码时,通常能预想到需要使用到的数据范围的大小。这样在处理一个数据时,可以从语言所提供的类型中选用最合适的类型来承载数据。
在C语言标准并未规定这些数据类型的大小范围,具体的实现交由了编译器和平台决定。
2. 用sizeof关键词来测量大小
和int
一样,sizeof
是C语言中的一个关键词。它是英文size of
连起来的合成词。翻译成中文就是什么东西的大小的意思。它能够测量C语言各种实体所占用的字节大小。
如果我们想看int
所占用的字节大小,可以这样写sizeof(int)
。执行后这段代码后,它的测量结果是一个整型。我们可以借助printf
函数将测量结果显示在控制台上。我们现在可以假设sizeof
返回的结果是int
类型的,在printf
函数中使用占位符%d
。而更准确的用法,应该用%zu
。
测量int
类型所占用的字节大小,并将结果打印在控制台上的代码如下:
printf("%d\n", sizeof(int));
sizeof
后面既可以跟 类型,也可以跟 变量、常量。
- 跟类型,测类型所占用字节的大小。
- 跟变量,测变量的类型所占用字节大小。
- 跟常量,测常量的类型所占用字节大小。
三种情况的示例代码。
int a; printf("sizeof int = %d\n", sizeof(int)); // 1.测类型所占用字节的大小 printf("sizeof a = %d\n", sizeof(a)); // 1.测变量的类型所占用字节大小 printf("sizeof 123 = %d\n", sizeof(123)); // 1.测常量的类型所占用字节大小
测试C语言提供的各种整型类型的大小
printf("sizeof char=%d\n", sizeof(char)); printf("sizeof short=%d\n", sizeof(short)); printf("sizeof int=%d\n", sizeof(int)); printf("sizeof long=%d\n", sizeof(long)); printf("sizeof long long=%d\n", sizeof(long long));
结果:char,short,int,long,long long分别占用了1,2,4,4,8个字节。至此,我们已经得知了它们所占字节大小,并且验证了可以表示越大范围的数据类型所占用的字节越多。
值得注意的是
int
和
long
均占用4个字节。这并未违反C语言标准,C语言标准规定高级别的类型取值范围不得小于低级别的类型,但是它们可以是一致的。
3. 三位二进制表示的数值范围
char
,short
,int
,long
,long long
分别占用了1,2,4,4,8个字节。而每个字节由8个晶体管组成,每个晶体管状态我们称之为位。那么char
,short
,int
,long
,long long
分别占用了8,16,32,32,64位。
太多的位不利于理解原理,暂时把问题简化一下,试试看位数减少到3。然后,分析3位的组
合,它能表示多大范围的数值.
晶体管状态 |
二进制数据 |
十进制数据 |
关关关 |
000 |
0 |
关关开 |
001 |
1 |
关开关 |
010 |
2 |
关开开 |
011 |
3 |
开关关 |
100 |
4 |
开关开 |
101 |
5 |
开开关 |
110 |
6 |
开开开 |
111 |
7 |
三位二进制组成的数据类型,可以表达2的3次方也就是8个数值。如果从0开始,那么可以表达从0到7的
数据范围。得出结论:如果不考虑负数,那么整型数据类型可以表达的数据范围是 假设,位数为n,则数据范围从【0】开始,到【2的n次方-1】的数值范围。
那负数
怎么办?我们需要拿出一个位来作为符号位。用来表示这个数据是正数还是负数。在IEEE标准中,这个符号位存在于二进制的最高位。用三位二进制来示范这种情况。
晶体管状态 |
二进制数据 |
十进制数据 |
关关关 |
000 |
0 |
关关开 |
001 |
1 |
关开关 |
010 |
2 |
关开开 |
011 |
3 |
开关关 |
100 |
-4 |
开关开 |
101 |
-3 |
开开关 |
110 |
-2 |
开开开 |
111 |
-1 |
加上符号之后,现在取值范围变为负4到3了。红色字体的为最高位,最高位为1的表示负数。你可能会觉得有点奇怪,为什么3的二进制是011
,而负3却是101
呢?如果简单的加一个符号位,为什么不用111呢?那我们看看如图中所示的3与负3相加的运算结果。
会惊奇地发现,用101来表示负3与用011表示的正3相加。结果为1000,但是由于仅有3位二进制来保
存数据,最高位1被丢弃了。结果为000,居然得到了正确的结果0。
4.数值的补码表示法
时钟是一个圆被分成了12个点,让我们假设这个时钟一步只能走一个整点。那么这个时钟只有12种不同的模式,我们把12称之为时钟的模。
现在指针指向了5点,我们要让指针回到0点。一个办法是直接回退5个小时(5-5)。
另一个办法是继续往前走7个小时(5+7)。
在第二种办法中,5+7=12,而12刚好为时钟的模,时钟指向12的同时,也正好指向了0。
要让指针回到0点,只需要让它加上模与当前的时间的差即可。
因此,指针回退5小时与指针前进7小时是等价的。我们可以用指针前进来代替指针后退。
将这种思想带入到上面讨论的三位二进制当中。三位二进制能表示8中不同的模式,因此它的 模 为8。要让3回到0,我们可以让3减去3,也可以让3加上 模与3的差,即8-3=5。因此,我们可以把-3在三位二进制中用5的二进制101表示。
这种将用加法来等效减法的二进制表示法被称之为补码表示法。
正数的补码就是其二进制本身。
而正数对应的负数的补码为:(模 - 正数)的二进制。
000 |
0 |
|||
001 |
1 |
|||
010 |
2 |
|||
负数 |
模减去正数 |
补码 |
011 |
3 |
-4 |
8-4=4 |
100 |
100 |
-4 |
-3 |
8-3=5 |
101 |
101 |
-3 |
-2 |
8-2=6 |
110 |
110 |
-2 |
-1 |
8-1=7 |
111 |
111 |
-1 |
补码表示法既通过最高位,区别了正数和负数。并且,巧妙地应用了溢出,所得到的计算结果也是正确的。类似于钟表仅需要向前走就可以实现减法,计算机的电路设计中,也只需要设计加法电路。极大地简化了计算机内部电路的复杂程度。
求一个正数对应的负数的补码的第二种办法:
- 先写出这个正数的二进制。
- 从二进制的右边开始,遇到第一个1之前,全都填0。
- 遇到第一个1之后,把1填下来。
- 1之后的全部取反。
从右往左:未遇到1填0,遇到1填1,然后全部取反
十进制0-1-2-3-4整数二进制000001010011100补码000111110101100
5.各种整型类型的数值范围是多少
类型 |
sizeof大小 |
二进制位数 |
取值范围算式 |
取值范围 |
char |
1 |
1×8 = 8位 |
-[2的7次方] ~ +[2的七次方 - 1] |
-128 ~ +127 |
short |
2 |
2×8 = 16位 |
-[2的15次方] ~ +[2的15次方 - 1] |
-32,768 ~ +32,767 |
int |
4 |
4×8 = 32位 |
-[2的31次方] ~ +[2的31次方 - 1] |
-2,147,483,648 ~ +2,147,483,647 |
long |
4 |
4×8 = 32位 |
-[2的31次方] ~ +[2的31次方 - 1] |
-2,147,483,648 ~ +2,147,483,647 |
long long |
8 |
8×8 = 64位 |
-[2的63次方] ~ +[2的63次方 - 1] |
-9,223,372,036,854,775,808 ~ +9,223,372,036,854,775,807 |
次方数比位数少一,是因为最高位被用去做符号位了。
6. 无符号整型
如果你确定你不会用到负数,那么请使用unsigned
关键词。表明这个数据类型,是不带有符号位的。既然不带有符号位了,那么原本留给符号位的那一个二进制位,可以用来表示数值。
类型 |
sizeof大小 |
二进制位数 |
取值访问算式 |
取值范围 |
unsigned char |
1 |
1×8 = 8位 |
0 ~ +[2的8次方 - 1] |
0 ~ +255 |
unsigned short |
2 |
2×8 = 16位 |
0 ~ +[2的16次方 - 1] |
0 ~ +65,535 |
unsigned int |
4 |
4×8 = 32位 |
0 ~ +[2的32次方 - 1] |
0 ~ +4,294,967,295 |
unsigned long |
4 |
4×8 = 32位 |
0 ~ +[2的32次方 - 1] |
0 ~ +4,294,967,295 |
unsigned long long |
8 |
8×8 = 64位 |
0 ~ +[2的64次方 - 1] |
0 ~ +18,446,744,073,709,551,615 |