变量和数据类型(二)
进制
二进制
二进制是计算技术中广泛采用的一种数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”。
- 数据在计算机中主要以补码的形式存储。
- 标准的C语言不支持二进制的书写,只是有的编译器进行了扩展,才支持书写二进制。
- 区分二进制,八进制和十进制通常根据数据的前缀和后缀。二进制的前缀:0b(不区分大小写);二进制的后缀B。
//合法的二进制
int a = 0b101; //换算成十进制为 5
int b = -0b110010; //换算成十进制为 -50
int c = 0B100001; //换算成十进制为 33
//非法的二进制
int m = 101010; //无前缀 0B,相当于十进制
int n = 0B410; //4不是有效的二进制数字
八进制
八进制,Octal,缩写OCT或O,一种以8为基数的计数法,采用0,1,2,3,4,5,6,7八个数字,逢八进1。一些编程语言中常常以数字0开始表明该数字是八进制。
- 八进制的前缀:0(0不是o); 八进制的后缀:O
//合法的八进制数
int a = 015; //换算成十进制为 13
int b = -0101; //换算成十进制为 -65
int c = 0177777; //换算成十进制为 65535
//非法的八进制
int m = 256; //无前缀 0,相当于十进制
int n = 03A2; //A不是有效的八进制数字
十六进制
十六进制(英文名称:Hexadecimal),同我们日常生活中的表示法不一样,它由0-9,A-F组成,字母不区分大小写。与10进制的对应关系是:0-9对应0-9,A-F对应10-15。
- 十六进制的前缀:0x或者0X(不区分大小写);十六进制的后缀:H
/合法的十六进制
int a = 0X2A; //换算成十进制为 42
int b = -0XA0; //换算成十进制为 -160
int c = 0xffff; //换算成十进制为 65535
//非法的十六进制
int m = 5A; //没有前缀 0X,是一个无效数字
int n = 0X3H; //H不是有效的十六进制数字
进制的输出
short | int | long | |
---|---|---|---|
八进制 | %ho | %o | %lo |
十进制 | %hd | %d | %ld |
十六进制 | %hx 或者 %hX | %x 或者 %X | %lx 或者 %lX |
十六进制数字的表示用到了英文字母,有大小写之分,要在格式控制符中体现出来:
- %hx、%x 和 %lx 中的
x
小写,表明以小写字母的形式输出十六进制数; - %hX、%X 和 %lX 中的
X
大写,表明以大写字母的形式输出十六进制数。
八进制数字和十进制数字不区分大小写,所以格式控制符都用小写形式。如果你比较叛逆,想使用大写形式,那么行为是未定义的,请你慎重:
- 有些编译器支持大写形式,只不过行为和小写形式一样;
- 有些编译器不支持大写形式,可能会报错,也可能会导致奇怪的输出。
计算机内存数值存储方式
原码
一个数的原码(原始的二进制码)有如下特点:
-
最高位做为符号位,0表示正,为1表示负。
-
其它数值部分就是数值本身绝对值的二进制数。
-
负数的原码是在其绝对值的基础上,最高位变为1。
下面数值以1字节的大小描述:
十进制数 | 原码 |
---|---|
+15 | 0000 1111 |
-15 | 1000 1111 |
+0 | 0000 0000 |
-0 | 1000 0000 |
反码
-
对于正数,反码与原码相同。
-
对于负数,符号位不变,其它部分取反(1变0,0变1)。
十进制数 | 反码 |
---|---|
+15 | 0000 1111 |
-15 | 1111 0000 |
+0 | 0000 0000 |
-0 | 1111 1111 |
补码
值得注意的是,原码和反码都不适合加减的运算,所以引入了补码的概念,这也是就为什么在计算机系统当中,数据大都以补码形式存储的原因。
在计算机系统中,数值一律用补码来存储。
补码特点:
-
对于正数,原码、反码、补码相同。
-
对于负数,其补码为它的反码加1。
-
补码符号位不动,其他位求反,最后整个数加1,得到原码。
十进制数 | 补码 |
---|---|
+15 | 0000 1111 |
-15 | 1111 0001 |
+0 | 0000 0000 |
-0 | 0000 0000 |
补码的意义
-
统一了零的编码。
用8位二进制数分别表示+0和-0
十进制数 原码 +0 0000 0000 -0 1000 0000 十进制数 反码 +0 0000 0000 -0 1111 1111 不管以原码方式存储,还是以反码方式存储,0也有两种表示形式。为什么同样一个0有两种不同的表示方法呢?但是如果以补码方式存储,补码统一了零的编码:
十进制数 补码 +0 0000 0000 -0 10000 0000由于只用8位描述,最高位1丢弃,变为0000 0000 -
将符号位和其它位统一处理,使得利用补码的加法和减法运算不会出问题。
-
将减法运算转变为加法运算。
-
两个用补码表示的数相加时,如果最高位(符号位)有进位,则进位被舍弃。
注意
- 赋值的时候(输入),赋值的是十进制,给的是原码。如果赋值的是八进制或者十六进制给的是补码。
- 打印的时候(输出),十进制打印要的是原码,如果是十六进制或者八进制打印要的是数的补码。
char num = 129;//赋值的是十进制,给的是原码
printf("num = %d\n");//输出-127,十进制打印,打印的是原码
解析:
第一步:129赋值的时候是十进制,给的是原码。129的原码=反码=补码=1000 001。
第二步:但是num是有符号数类型,最高位1,计算机这是一个负数的补码(数据在计算机中存储都是以补码的形式存储)。
第三步:打印的是十进制,要的是原码,1000 0001被计算机看作是补码,负数的补码求反码得到1111 1110,负数的反码求原码得到1111 1111-->-127。