类型的本质:对变量、类型、指针的理解

核心观点:类型约定了对数据的解释方式

信息和数据

来自 wikipedia 的定义

https://en.wikipedia.org/wiki/Information

https://en.wikipedia.org/wiki/Data

wikipedia 上的定义真的是太晦涩了

在我的理解中,数据就是不带有任何属性的数字。例如一个数字1,就是一个单纯的数据。

仅通过一个数字 1,你是无法得到任何信息的,因为你不知道这个1到底代表什么意思。只有结合具体的语境,你才能从中获得有用的信息。

例如1本书、1个人、1头猪等等

上面的书、人、猪实际上就是对数据的解释方式。他们分别将 1 解释为书的数量、人的数量、猪的数量。

因此为了获取信息,除了知道数据本身外,你还得需要知道对数据的解释方式。

所以,信息 = 数据 + 数据的解释方式

想一想谍战片子里面的电报机,电报机所发送的实际上是一些长短不一的摩尔斯电码,这些摩尔斯电码就是数据,外部人员不知道这些电码代表的是啥,但是专业的谍报人员对其翻译后,就可以从其中获取到有用的信息。这里的翻译实际上就是在对数据进行解释。翻译工作可能是依靠一个密码本来进行的,密码本上约定了数据的解释方式。

例子
l i v e

这四个字母,如果用从左至右的方式来解释,将是 live,如果用从右至左的方式来解释,将是 evil。

1 0 1 1

这四个数字,如果每两个一组进行解释,将会得到

10 11

如果每四个一组进行解释,将会得到

1011

同样的数据,使用不同的解释方式,就能得到不一样的信息。

类型约定了对数据的解释方式

c 语言中有如下一些基础数据类型,摘自https://www.runoob.com/cprogramming/c-data-types.html

整数类型

类型 存储大小 值范围
char 1 字节 -128 到 127 或 0 到 255
unsigned char 1 字节 0 到 255
signed char 1 字节 -128 到 127
int 2 或 4 字节 -32,768 到 32,767 或 -2,147,483,648 到 2,147,483,647
unsigned int 2 或 4 字节 0 到 65,535 或 0 到 4,294,967,295
short 2 字节 -32,768 到 32,767
unsigned short 2 字节 0 到 65,535
long 4 字节 -2,147,483,648 到 2,147,483,647
unsigned long 4 字节 0 到 4,294,967,295

浮点类型

类型 存储大小 值范围 精度
float 4 字节 1.2E-38 到 3.4E+38 6 位小数
double 8 字节 2.3E-308 到 1.7E+308 15 位小数
long double 16 字节 3.4E-4932 到 1.1E+4932 19 位小数

再回顾一下我的核心观点:类型约定了对数据的解释方式

在这里我就取 char 类型和 short 类型来解释。char 类型的大小是 1 字节,short 类型的大小是 2 字节。一字节 byte 等于 8 bit,一个 bit 就是一个二进制位,值为 0 或 1。实际上 char 约定了以 8 个 bit 为一组来解释,而 short 则约束了以 16 个 bit 为一组来解释。

现在有一个 16 个 bit 大小的空间,空间里的内容为:

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1

如果用 char (每 8 个 bit 为一组)来解释,则可以解释为两个 char,char0 = 00000000 = 0,char1 = 00000001 = 1。

如果用 short (每 16 个 bit 为一组)来解释,则可以解释为 1 个 short,short0 = 0000000000000001 = 1。

变量(variable) = 地址(address) + 类型(type)

一个变量由两个要素组成,分别是变量的地址,以及变量的类型。

address 确定了存放变量的字面值的空间位置

type 约定了如何解释这段空间

在 c 语言中,初始化一个变量的方式是:

char a = 1;

例如在这里,

  • 变量 a 的 address 是 &a
  • 类型是 char,它决定了将会以 8 个 bit 为单位解释 address 中的内容
  • a 的字面值是 1,字面值是通过 address 和 char 通过得到的

在 address 处存放了数据本体,利用 type 来解释数据,最终得到字面值这个信息。

对变量的访问是通过访问该变量的地址来完成的

在 c 语言中,对于变量的访问实际上都是通过访问该变量的地址来完成的。但是只有地址还不够,如何解释这篇地址的内容,是以 8 个 bit 为单位亦或者是以 16 个 bit 为单位,这就需要用到类型了。

变量在初始化时,会被分配一个地址。这个地址就是变量的家,变量的地址是不会发生改变的,它一辈子只会有一个家,不会搬家。

变量的初始化
char c = 1;

在这行代码里,实际上会有如下两步操作:

  1. 为变量 c 分配一个空间,这个空间就是 c 的家,假设 c 住在地球一号村,二号楼0号房间吧,就用 0x120 来表示 c 的地址吧。

  2. 将 0x120 ~ 0x128 这 8 个 bit 的空间里的内容初始化为 1(其实 c 里面地址的单位是 1 个 byte,而非 bit),变成下面这个样子:

    image

    为何是 8 个 bit 而不是其他数字的 bit?这是 c 的类型所决定的,因为类型是 char,所以是 8 个 bit。

对 c 的修改
c = 2

实际上还是分为两步:

  1. 第一步还是先得到 c 的地址,之前说过变量的地址是不会发送改变的,因此这里变量 c 的地址也就是 0x120

  2. 将 0x120 ~ 0x128 这 8 个 bit 的空间里的内容初始化为 2,变成了下面这样:

    image

对 c 的访问
char i = c;
  1. 得到 c 的地址 0x120
  2. 对 0x120 ~ 0x128 这 8 个 bit 大小的空间进行解释。类型约定了对数据的解释方式,而这里的类型是 char,所以用 8 个 bit 的方式来解释。
  3. 对 i 的操作也是类似的...

指针

指针变量本质和普通的变量没有太大区别,依旧由值和类型组成,同样也会被分配一个地址。

但是它相比普通变量多了一个 * (dereference) 操作。dereference 是指针变量所特有的操作,普通的变量是无法进行 dereference 操作的,否则会发生编译错误。

定义一个指针变量
char* p = 0x120;

p 的值是 0x120 ,p 的类型是 char* (指向 char 类型的指针)。

char* = char + *
* 表明这个变量是一个指针,因此有 dereference 能力
char 约定了在 dereference 时,它将会以 8 个 bit为 单位来解释
deference

通过 dereference ,可以对地址中的内容进行操作。

*p = 1

这句代码将会把 0x120 ~ 0x128 这 8 个 bit 的空间里的内容置为 1。

image

对指针变量的修改
p = 2

与上面所说的变量的修改过程是一样。

一些具体的例子

基本原则
  1. 变量 = address + type
  2. 变量会被分配一个地址,且这个地址是固定的
  3. 对变量的访问是通过访问变量的地址来完成的,变量的类型约定了对地址中内容的解释方式
例子1:通过指针来修改变量的值
char c = 1;			// 为 c 分配地址,假设 c 的地址是 0x120,c 的值是 1,0x120 ~ 0x128 这 8 个 bit 的内容是 1
char* pc = &c;		// pc 是一个指针,它的值是 c 的地址,则 pc 的值是 0x120
*pc = 2;			// dereference 操作,将 0x120 ~ 0x128 这 8 个 bit 的内容设置为 2
printf("%d",c);		// 取 0x120 ~ 0x128 这 8 个 bit 的内容进行解释,得到 2,因此输出 2
例子2:指向指针的指针
char* pc = null;	// 为 pc 分配地址,假设 pc 的地址是 0x1200,pc 的值是 0,0x1200 ~ 0x1220 这 32 个 bit 的内容是 0(在 32 为环境下,指针的大小是 32 bit)
char** ppc = &pc;  // ppc 的值为 0x1200
char c = 1;		   // 为 c 分配地址,假设 c 的地址是 0x120,c 的值是 1,0x120 ~ 0x128 这 8 个 bit 的内容是 1
*ppc = &c;		   // 将 0x1200 ~ 0x1220 这 32 个 bit(char*) 的内容设置为 0x120,此时 pc 的值为 0x120 了
*pc = 2;		   // 取 0x120 ~ 0x128 这 8 个 bit(char) 的内容设置为 2, 此时 c 的值变成 2 了
posted @ 2021-06-19 17:19  机智的小小帅  阅读(786)  评论(0编辑  收藏  举报