Linux C程序设计 - 内存数据格式和进制数

1计算机理解的进制数

学习一门编程语言,无论是C/C++还是JAVA等等任何一门编程语言,都没有捷径,唯一的捷径就是多敲代码,多思考。把自己的疑问通过代码来表达出来,然后,验证问题、解决问题。

但是,在学习编程之前,我们还是需要一些基础知识的准备,例如了解数据在内存中存储的形式、二进制、十六进制的计算等等。

2内存中数据存储格式

我们渡过的每一天都是从白天到黑夜,再从黑夜到白天这样循环重复着,如同中华文化里的太极,表示着阴和阳之间的相互转换。这个世界上,任何事情都有两面性,也就是阴和阳。

同样,计算机也是由阴和阳组成。我们知道,计算机是一台电子设备,是由N多个二极管、三极管组成。这些二极管和三极管的特性就是“截止和导通”;“截止”和“导通”,就形成了电路的“开”和“关”。

计算机中的内存设备,就是由N多二极管、三极管组成,里面就存放着电路的打开和关闭的状态。最终,电路的打开和关闭的状态,就是由0和1这两种数值来表示。

首先,我们来看一个电影情节:有2个黑帮在进行约谈,随时可能会发生冲突。一个黑帮的头领对手下说:

(1) 在交谈的最后,如果我把吃饭的筷子放在碗上,就表示和谈,不要动手;

(2) 如果我把筷子放在碗的旁边,就表示谈判破裂,你们马上动手;

在这个电影情节中,我们得到这样的信息:

(1)碗是一个容器,可以把筷子放在上面;

(2)如果碗里面放筷子,表示和谈,不动手;

(3)如果碗里面不放筷子,表示谈判破裂,马上动手;

那么,这个碗就是一个“容器”,存放了我们需要的信息。

在计算机中,内存是存放计算机数据的地方,就是一个“容器”,可以存放二极管的“截止”和“导通”状态,就是存放电路的“打开”和“关闭”状态。可以表示为:

(1)电路的“打开”状态用1表示;

(2)电路的“关闭”状态用0表示;

那么,当我们按下键盘的某个按键时,就在内存的某个地方,存放1数值;当键盘弹起的时候,内存中存储键盘按下状态的地方,从1值变为0值。那么,计算机就可以知道键盘的按下和释放的状态。

此时,我们知道,计算机的内存,存放0和1这样的数据。在计算机中,存储数据的最基本单位是字节(Byte),一个字节由8位(bit)组成。一个位(bit)就是就是存储一个二进制数据。

3十进制数据

在讲解二进制数据之前,我们先来看看我们最常用的十进制数据。

从小学读书起,我们就开始学习数学,最简单的加法有:

5 + 3 = 8;

5 + 5 = 10;

10 + 16 = 26;

看到这样的加法算术很简单,它只有一个规则:

(1)个位数与个位数相加,满10进1;

(2)十位数与十位数相加,满10进1;

(3)百位数与百位数相加,满10进1;

...

以此类推,这种规则表示的数,我们称为:十进制数;

表示十进制数的元素就有:

0,1,2,3,4,5,6,7,8,9

这样的10个数值;

所以,从我们最常见的算术开始,我们了解了十进制数。它的规则就是:满10进1;那么,根据这个规则,我们可以定义N进制数,它的规则就是:

(1)表示N进制数的元素,有N个符号;

(2) 数据的表示,是满N进1;

4二进制数据

通过上一节的讲解,我们知道二进制就是由0和1组成的数字,它表示电子设备的打开和关闭状态。计算机中存储的任何数据都是二进制数据。

例如十进制3这个数值,在计算机中都表示成的二进制数据是11这样数值。如果十进制3这个数值存放到1个字节中,1个字节使用8位表示,那么,表示的数值是 0000 0011,所以,表示8位二进制数据。

根据上面提到N进制数规则,我们定义二进制数的规则是:

(1)表示二进制数的元素有 2 个符号,就是0和1这两个数值;

(2)二进制数的表示是满2进1;

知道了二进制数据的表示方法,那么,我们试着把十进制19这个数值的二进制数据写出来。

把十进制数据转换成二进制数据,使用的方法是:除2取余法,计算过程如下:

19/2 = 9余1

9/2 = 4余1

4/2 = 2余0

2/2 = 1余0

1/2 = 0余1

除到商为0的时候停止;

然后,从最末尾的余数开始往上取,得到10011这个二进制数据。所以,十进制19这个数值的二进制数据就是10011。如果把十进制19这个数值存放到1个字节的变量中,那么,在1个字节的内存中表示为0001 0011,因为1个字节是8位,上面我们求出10011二进制数据占据了5位,那么,剩下的高3位没有数据填充,所以,填充0值。

所以,我们可以总结十进制转二进制的方法:

(1) 采用除2取余法;除到商为0的时候停止。

(2)余数从下往上取;

(3)高位补零;

现在我们试着把二进制转换为十进制。在转换之前,我们先看看十进制表示的一个例子。例如189这样的一个数值,在数值序列中,从右边开始算起,从0开始计算,就有:

9在第0位,8在第1位,1在第2位,那么,就可以表示为:

1*10^2 + 8*10^1 + 9*10^0 = 100 + 80 + 9 = 189

那么,是十进制表示,所以,基数为10,例如第2位,就有10^2表示10的2次方,就是10*10,这就是第2位的权重值;注意:在数学计算中,任何数的0次方,都等于1。 所以有:

1*10^2 + 8*10^1 + 9*10^0

= 1*100 + 8*10 + 9*1

= 100 + 80 + 9

= 189

所以,我们可以总结N进制数值的表示算法:

(1)每个位置上的数值,与权重值相乘,然后求和;

(2)权重值是N^x,表示N的x次方,x是数值在数值序列上的位置;位置从右边开始算,从0开始;

同理,我们就把10011这个二进制转换为十进制,也是使用相同的算法。

把10011这个数值序列解开,从右边开始计算,第0位是1,第1位是1,第2位是0,第3位是0,第4位是1;

那么是二进制表示,所以,基数为2,例如第3位,就有2^3的权重,就有:

1*2^4 + 0*2^3 + 0*2^2 + 1*2^1 + 1*2^0

= 16 + 0 + 0 + 2 + 1

= 19

所以,我们把19这个十进制转换成了10011二进制数据,再把二进制数据转换为十进制数据。

再多举一个例子,把18这个数值转换为二进制表示,有:

18/2 = 9余 0

9/2 = 4余 1

4/2 = 2余 0

2/2 = 1余 0

1/2 = 0余 1 //除到商等于0的时候,停止计算;

然后,从下往上取余数,得到10010二进制数据。然后,10010二进制转换为十进制数据,有:

1*2^4 + 0*2^3 + 0*2^2 + 1*2^1 + 0*2^0

= 16 + 0 + 0 + 2 + 0

= 18

通过这些例子的分析,我们讲解了二进制的表示形式和二进制与十进制数值间的相互转换。

5十六进制数据

在介绍十进制数的时候,我们已经定义了N进制数,它的规则就是:

(1)表示N进制数的元素有N个符号;

(2)满N进1;

那么,十六进制数就是有16个符号表示,如下:

0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F

其中字符A表示10数值,字符B表示11数值,字符C表示12数值,字符D表示13数值,字符E表示14数值,字符F表示15数值。注意:这个字符,也可以使用小写字符a、b、c、d、e、f表示。

在学习二进制数据的时候,我们知道,把一个十进制数据转换N进制数据,采取除N取余法。所以,把一个十进制数据转换为十六进制,就是采取:除16取余法。例如,把十进制数18这个数值,转换为16进制,有如下的计算:

18/16 = 1余 2

1/16 = 0余1

然后,从下往上取余数,得到十六进制数12这样的数值。但是,我们有些疑惑,当我们看到12这个数值的时候,如果不表明是十六进制,我们可能会认为是十进制数据。

所以,在计算机系统中,我们定义十六进制数,使用0x前缀表示。所以,上面计算出来的十六进制数据就可以表示为0x12。当我们看到一个数值,如果是以0x开头,就表示这个数据是十六进制数据。

那么,我们把十六进制数0x12数值,转换为十进制数,算法与二进制转换为十进制数一样。对于0x12数值序列,第0位是2,第1位是1,所以有:

1*16^1 + 2*16^0

= 16 + 2

= 18

此时,就可以把十六进制0x12数值对应的十进制计算出来了。我们再计算一个例子,计算十进制是169的数值,转换为十六进制,有:

169/16 = 10余 9

10/16 = 0余 10

其中,十进制10数值使用十六进制字符A表示,所以,得到的十六进制数是0xA9。注意,对于10~15的数值,在十六进制中,使用字符A~F(或者小写字母a~f)进行表示。例如十进制15这个数值,使用十六进制表示,就是0xF。

现在,我们把0xA9这个十六进制转换为十进制,计算方式如下:

A*16^1 + 9*16^0

= 10 * 16 + 9 * 1

= 160 + 9

= 169

注意,在计算的时候,十六进制的字符A表示十进制的10这个数值。

6有符号数和无符号数

学习了二进制数据,我们知道,在计算机系统中,存储的任何数据都是以二进制数据的格式存储。存储数据的最小单位是字节(Byte),一个字节的容量是八位(bit),可以存储8个二进制数据。在讲解“有符号数”和“无符号数”之前,我们先来举一个例子。

例如,有个人(称呼A)去爬山,半路上碰到一个朋友,朋友送了他一瓶水,此时A手上拥有一瓶水;那么,有如下的情况:

(1) 如果A觉得渴,那么,A觉得手上的这瓶水很宝贵,就把这瓶水喝掉;

(2) 如果A觉得不渴,那么,A觉得手上的这瓶水很重,麻烦,就丢掉;

(3) A手上的那瓶水,永远是那瓶水,本身没有任何变化。但是,A以不同的角度来看这瓶水,那么,会得到不同的结果。

在这个例子中,可以进行比较,如下:

(1)人员A就如同一个计算机系统;

(2)人员A手上拿有一瓶水,就如同计算机内存中,一个字节存储的一个数值;

(3)例如,在内存的一个字节中存储255这个整数值。那么,一个字节中的255这个数值,永远是255,不会有任何改变。但是,计算机系统把255这个数值,以不同的角度来看待,会有不同的结果。

那么,在计算机系统中,可以把内存中存储的数值当做“有符号数”和“无符号数”来看待。同一个数值,以不同的角度来看待,有不同的结果。

下面,我们来看看计算机系统对“有符号数”和“无符号数”的处理。

有符号数的定义是:字节的最高位作为符号位,其余的是数值位。例如一个字节中存储的二进制数为1100 1000,最高位1作为符号位,其余的7位100 1000作为数值位。

那么,符号位占据1位,就有0和1这样的两种数值,就有:

(1)如果符号位为0,那么字节中存储的数值是正数;

(2)如果符号位为1,那么字节中存储的数值是负数;

对于1100 1000这样的二进制数据,符号位是1,就表示负数。在有符号数中,表示负数的算法是:

(1)把数值位中存储的二进制数据,每个位都取反,就是原来为0的值变为1,原来为1的值变为0;

(2)给对取反后的二进制数据加1,得到的数值就得到负数值;

所以,有符号数可以表示正数,也可以表示负数。

无符号数的定义是:没有符号位,所有的位数都是数值位。所以表示的都是正数。

例如1100 1000这个数值,如果作为有符号数看待,那么符号位是1,数值位是100 1000。所以,符号位是1,所以,这个数据是负数。然后,表示成十进制时,对数值位的操作是:

(1)数值位取反,得到011 0111;

(2)对取反后的数值 011 0111加1得到011 1000,数值位的值为56;

那么,1100 1000这个二进制数据表示为“有符号数”时,就是-56这个数值。

如果作为无符号数看待,那么,就没有符号位,所有的位数都是数值位,所以11001000都作为数值位,表示的十进制数值是180。

例如,0111 0011这个数值,如果当做“有符号数”看待,那么,其符号位是0,所以,表示正数,数值位是115,所以,表示正115这个数值。如果当做无符号数看待,所有位都是数值位,计算得到115这个数值,所以,表示正115。所以我们可以总结:

(1)无符号数,总是表示正数。所有位数都表示数值位。

(2)有符号数,可以表示正数和负数,最高位是符号位,其余位都是数值位。如果符号位是0,则表示正数;如果符号位是1,则表示负数。对于负数的表示方法是:数值位全部取反,再加1,得到的数值就是负数值。

7 ASCII

在计算机系统中,存储在内存中的任何数据,都是使用二进制形式进行存储。例如,十进制2这个数值,转换为二进制是10,如果存储到内存的一个字节中,就是0000 0010,因为一个字节是8位的容量,而二进制10只占用2个位,所以,高位用0补全。

此时,我们可以把一个数值存储到一个字节中。那么,对于计算机处理的'A'、'B'、'C' …等字符,怎么样处理?怎么样存储到内存中?

为了解决这个问题,计算机使用了ASCII编码。ASCII(American Standard Code for Information Interchange,美国信息互换标准代码,ASCII)是基于拉丁字母的一套电脑编码系统。它主要用于显示现代英语和其他西欧语言。它是现今最通用的单字节编码系统。

ASCII编码就定义了特定的符号,对应特定的数值,例如'A'符号对应的数值是65,那么,我们只需要把65这个数值存储到内存中,就是把'A'符号存储到了内存中。

ASCII编码的对照表如下。


可以看到,字符'a'和'A'都使用了不同的数值进行表示。如果内存中存储了97数值,就可以表示'a'字符,如果存储了65数值,就可以表示'A'字符。

8总结

学习计算机软件编程,必须熟练掌握二进制、十进制、十六进制数据的应用。特别是面向计算机底层系统的开发,经常需要处理各种二进制、十六进制的数据。例如,在网络编程中,需要定义网络协议数据包,那么,一个字节就可以拆分成不同的数据位来表示不同的操作,就需要操作二进制数据。

所以,熟练掌握二进制、十进制、十六进制的应用非常重要。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342