二进制信息表示

问题初始来源:如何把一个数据按照字节,存储到一个char类型,长度为4的字符串数组中。

就是普通 的一个整数(可能为负数),这个整数占用4个字节空间

如何存储到char类型的字符型数组里面,再按照单个字节读取的形式,在电脑本地,将数据读取出来。

比较简单粗暴的方法:

1.循环读取,每次把整数的最小8位存进去,然后右移8位。

比较直接的方法就是:

char chrArr[10];
int intVal;
*((int*)charArr) = intVal;

我写了如下代码进行测试:

char chrArr[20];
int intVal = 1234;
*((int *)charArr) = intVal;

printf("%c", chrArr[0]);
printf("%c", chrArr[1]);
printf("%c", chrArr[2]);
printf("%c", chrArr[3]);

输出如下:
◆ 请按任意键继续...

将上述代码中的所有chrArr的元素,按照%d的格式输出,结果是:
-46400请按任意键继续...

可以看到,这仍然不是我们想要的结果,可以推断出,其实是由于负数的缘故。

将上述代码中的%c,替换成%u,输出结果是:
4294967250400请按任意键继续...

此时结果仍然是不对的,chrArr要转型,考虑到按照字节解析,排除负数的干扰,这里直接用unsigned char数组

于是,上述代码,最终变为:

int a = 1234;
char ch[100];
unsigned char chrArr[20];
int intVal = 1234;
*((int *)charArr) = intVal;

printf("%u", chrArr[0]);
printf("%u", chrArr[1]);
printf("%u", chrArr[2]);
printf("%u", chrArr[3]);

否则,需要将chrArr转型,也就是用(unsigned int)chrArr[0]

此时,输出结果为:
210400请按任意键继续...

4*256+210 就是1234

进一步解释一下,就有下面的式子A:

210 + 4256 + 0256256 + 0256256256

int val = *((int*)chrArr));

上面的代码,现在这个只是数组转成一个整数值

此处一定要吸取经验教训:
就是不要老是自己看书,要结合实践,要自己手写代码来测试各种情况。

下面来解释上面的式子A是什么意思:
256就是2的8次方,一个字节占有8位(也就是8个bit),一个整数就是4个8位的字符。
那分成4个8位,
高位是不是要乘以一个分量?
4个8位的数相加最多才1024.

此处可能有点难理解,因为正常我们转进制,都是乘以2,8, 10, 16的

可以这样想:

256其实就是就是256进制


100分成两位数可以怎么分?
其实是 10, 0,

1010 + 010

相当于0乘以10的0次方 加上 10 乘以 10 的平方

10进制表示法,每个数字最大10,


二进制:

10000000 10000001这两个二进制分开存

合起来的时候就可以看作是直接相加, 1000000010000001这个就是结果。

10000000*256 + 10000001

乘以256就是左移8位,

10000000 << 8 + 10000001

把一个整数拆开4个存,本来是百位的都变成个位了,恢复的时候,百位要变百位

如果上面的二进制没有看懂,可以看下面的解释:
合起来的意思:其实就是原始的值:
1000000010000001就是原始值
拆分完以后,就变成了两部分。
一共是16个bit

也就是拆分为两部分的后的结果为:

10000000 10000001

那么用什么运算,可以将上面这左右两部分数合成结果?

相加可以吗?

当然直接相加肯定是不行的。

需要将左边的数,左移8位,然后再相加,
将左边的部分左移8位,那么右边的部分就要补0
10000000向左移动8位,那么得到的结果就是
1000000000000000
乘以256,其实就相当于向左移动8位

说白了,你直接写<< 8也可以
然后整数是32位,

所以,要有左移24,16,8位

32位数字,最高8位拿出来
左移24位,是不是就是刚好在最高位

11000000 10000001 10000000 10100000 这是一个32位的整数

11000000 左移24位得到11000000000000000000000000000000
加上10000001左移16位得到100000010000000000000000
再加上10000000左移8位得到1000000000000000
再加上10100000左移0位得到10100000

将上述【得到】字样后面的数相加,
看是不是组成32位数字了

也就是移完24位加移完16位

11000000000000000000000000000000
加。 100000010000000000000000

11000000000000000000000000000000
加。 100000010000000000000000
加1000000000000000

11000000000000000000000000000000
加。 100000010000000000000000
加1000000000000000

11000000000000000000000000000000
加。 100000010000000000000000
加1000000000000000加再加10100000

得到如下结果

11000000100000011000000010100000

那么问题来了,11000000100000011000000010100000这个要怎么拆成4个8位数字?

取这个数的最低8位,就是10100000

11000000100000011000000010100000然后这个右移动8位再取最低8位

110000001000000110000000这个是移完8位的然后再取最低8位

直到整个数字移完

这个过程就是拆分

组合的过程你知道了,就是上面说的。

因为是字符型数组,数组0元素的最大范围就是255

1234存不进数组中

那结果怎么存储1234

除非数组0存12

已知,整数1234的二进制表示位:
100 1101 0010

也就是,整数1234的二进制表示是:
0000 0000 0000 0000 0000 0100 1101 0010

也就是,占用了char类型数组的4个元素

char ch[4];

char chrArr[20]

chrArr[0] 为 0000 0000

因为程序是小端程序

chrArr[1]为0000 0000
chrArr[2]为0000 0100
chrArr[3]位1101 0010

所以最低位是:1101 0010

这里说到的小端顺序就是,低地址位存储整数的 低位,也就是数组0号元素,存储最小的。

数组0存最小的,11010010

数组1存00000010

也就是1234这个数的低8位是1101 0010在chrArr[0]内部是直接存储的,这8位在内存中就是这样直接存储的,内部不用再考虑内部是否需要逆置顺序的问题。

也就是数组0就是11010010,

11010010的十进制就是210

所以,你代码里看到的数组0的结果是210

如果你按照%x进行打印,那么,打印出来的是结果就是11010010对应的十六进制,也就是d2

又因为,符号位是负数,大于127就是负数,210是不是大于127了?所以,除非用unsigned char这种无符号类型的

所谓符号位就是:最高位是符号位,如果最高位是0,则表示是正数;如果最高位是1,则表示是负数

本来,210存入char就是负数。

经验:

计算机无论怎么存储数据,都无所谓,看怎么解析,怎么存都是二进制,无论是int还是char还是double,还是float,无论什么数,本质都是二进制。

posted @ 2017-02-20 21:45  drfxiaoliuzi  阅读(1277)  评论(0编辑  收藏  举报