深入理解计算机系统(2.1)---信息的存储与值的计算

本文转载地址:http://www.cnblogs.com/zuoxiaolong/p/computer5.html

引言

我们很难想象,1和0这两个再简单不过的数字,给计算机科学带来了彻底的改变。对于无法与人脑相比的计算机来说,简单的1和0就是最适合它们的数字。不过1个1或者1个0往往代表不了任何意义,它们必须被赋予上下文,才能有具体的含义。比如,如果我们知道1和0是代表的布尔类型的值,那么我们就知道1是true,0是false。

对于二进制所表示的数字来说,主要有三种,即无符号、补码以及浮点数

由于计算机对于固定类型的二进制数字往往都是有位数限制的,比如int类型使用四个字节(32位二进制)来表示,因此在计算的时候,会发生溢出的情况,最简单的我们使用无符号整数0xFFFFFFFF与无符号整数0xFFFFFFFF相乘,则会产生溢出。

在产生溢出的时候,得出的结果往往会令人大跌眼镜。比如两个正数相乘可能得到负值,两个正数相加也可能得到负值。而对于不同的计算机来说,由于数值范围可能有所不同,因此掌握信息相关的内容对于写出跨平台的程序来讲也是很有帮助的。

信息的存储

大多数计算机使用8位的块,或者说字节,来作为最小的可寻址的存储器单位,而不是在存储器中访问单独的位。换句话说,我们在访问存储器的内容时,最小的访问单位一般是字节。

在我们编程的时候,往往会把虚拟存储器(virtual memory)抽象为一个字节数组,而每一个数组内的元素或者说字节都有唯一的地址(address),这些地址的集合就被称作虚拟地址空间。虚拟地址空间是为了给机器级的程序一个概念上的映像,实际上为了提供这个映像,内部的实现是非常复杂的。

十六进制表示法

对于机器来说,可能比较喜欢0和1,但是对于人类这种高级生物来说,1和0就有点不够看了。因此通常情况下,为了便于阅读,我们会使用十六进制去表示二进制。1位十六进制的数字可以表示4位二进制数字,因此一个字节就可以表示为0x00---0xFF。

有关十六进制、二进制以及十进制的转换,LZ这里就直接略过了,相信大部分人应该都对这个转换并不陌生。

每台计算机都有一个字长(word size),用于指明整数和指针数据的标准大小(nominal size)。而由于虚拟地址空间中的地址就是使用一个字来表示的,因此操作系统中的字长就决定了虚拟地址空间的大小。

比如32位操作系统下,最大内存就是232 = 4 * 210 * 210 * 210 B = 4GB,而在64位操作系统下,LZ还专门问了问群里的猿友,最终得到的结果是234GB。

数据大小

由于计算机位数的不同,会造成在数据类型的存储上,采用的位数略有不同,下表是在32位和64位机器下,C语言当中的数字数据类型需要的位数。

可以看出,对于长整形以及字符指针类型来说,在32位和64位系统下的字节数是不同的。特别的,对于指针类型来说,所有指针类型在32位下都是4位,而在64位下都是8位,这是由虚拟地址空间的地址位数或者说字长所决定的。

寻址和字节顺序

对于跨越多个字节的程序对象(程序对象指指令、数据或者控制信息等,是程序当中对象的统称)来说,我们需要制定两个规则,才能唯一确定一个程序对象的值。

比如对于int类型的值0xFF来说,如果我们要根据虚拟内存地址去获取这个整数值,那么首先我们需要知道它的起始虚拟内存地址是多少。另外,我们还需要知道,对于表示int类型的四个字节来说,这四个字节的排列顺序

对于第一个问题,由于大部分计算机都采用连续的内存地址去存储一个程序对象,因此我们称内存地址中最小的那个就是该程序对象的起始地址,也是该程序对象的地址。

对于第二个问题,一般有两种方式,即大端法和小端法。对于一个整数0x000000FF来说,我们假设它的起始地址为0x1,那么对于使用大端法规则的系统来说,0x1-0x4的虚拟内存所存储的值依次为0x00、0x00、0x00、0xFF,相反对于采用小端法规则的系统来说,0x1-0x4的虚拟内存所存储的值依次为0xFF、0x00、0x00、0x00。

强制类型转换

对于一个特定的数据类型来讲,计算机在解释这类数据的值的时候,是根据起始位置以及数据类型的位数来确定的。比如对于无符号int类型的数据来说,倘若我们知道它的起始位置为0x1,而当前的操作系统采取的是大端法规则,假设0x1-0x4的内存地址中存储的字节依次为0xFF,0xFF,0xFF,0xFF,由此计算机将会帮我们计算出这个无符号int类型的值为232-1,也就是无符号int类型的最大值。

这其中计算机是根据0x1-0x4这四个字节上的值,以及无符号int类型的解释方式,最终得到的这个无符号int类型的值。

由此可见,计算机在解释一个数据类型的值时主要有四个因素:位排列规则(大端或者小端)、起始位置、数据类型的字节数、数据类型的解释方式

对于特定的系统来说,前两种因素都是特定的,而对于后两种因素的改变,则可以改变一个数据类型的值的最终计算结果,这就是强制类型转换。对于大部分高级程序设计语言来讲,都提供了强制类型转换。

比如C语言,我们可以将一个无符号int类型的值强制转换为其它类型,在转换之后,对于上面四个因素之中,改变的是最后两个。为此我们写一个小程序来看下这个有意思的事情。

#include <stdio.h>

int main(){
    unsigned int x = 0xFFFFFF61;
    int *p = &x;
    char *cp = (char *)p;
    printf("%c\n",*cp);
}

这是一个简单的强制类型转换示例,可以看到我们将一个无符号int类型的值,先赋给了一个int类型的指针,又强制转换成了char类型的指针,最终我们输出这个char类型指针所代表的字符,结果的输出是一个a。

输出a的原因就是由上面的四个因素决定的,我们看这个具体程序上的四个因素。

1、cp指针的值与x变量的起始内存地址相等。(起始位置)

2、LZ的linux系统是小端表示法,也就是说假设x变量的起始内存地址为0x1,那么0x1-0x4的值分别为0x61、0xFF、0xFF、0xFF。(位排列规则)

3、char只占一个字节,因此会只读取0x61这个值。(数据类型的字节数,或者说大小)

4、0x61为十进制的97,对应ascii表的话,代表的是字符a,因此最终输出了a。(数据类型的解释方式)

可以看出,强制类型转换有时候会让结果变的让人难以预料,因此这种技巧一般不太推荐使用,但是这种手段也确实是程序设计语言所必需的。

字符串的表示

这一点其实上面我们已经提到了,我们知道97其实代表的是字符‘a‘,而这个的由来就是根据ascii表来的,我们在linux系统上可以输入man ascii命令来查看。

代码的表示

二进制如何表示代码?

其实这些都是编译器的责任了,我们只需要写出像上面那个小程序一样的人们可以看懂的代码,编译器便会帮我们将其翻译成对应的机器所认识的二进制序列。从这个角度上来讲,程序语言其实就是一个二进制序列的简单描述,它提供我们更简单的编写计算机可以执行的二进制序列的方式。

文章小结

本次我们初步探索了信息的存储以及信息所代表的结果的计算,这些内容都比较基础,相信不难看懂。

时间: 2024-11-05 16:26:00

深入理解计算机系统(2.1)---信息的存储与值的计算的相关文章

信息的存储与值的计算

信息的存储与值的计算 前言 我们很难想象出来,计算机只能识别0和1这样再简单不过的数字,却给人们带来了巨大的变化.对于无法与人脑相比的计算机来所,简单的1和0就是适合他们的数字.不过呢,一个1或者1个0往往代表不了什么意义,,他们必须被赋予上下文,才能有具体的含义.比如,如果我们知道1和0代表的布尔类型的值,那么我们就知道1是true,0是false. 对于二进制所表示的数字来说,主要有三种,即无符号,补码以及浮点数. 由于计算机对于固定类型的二进制数字往往都是有位数限制的,比如int类型使用四

深入理解计算机系统(1.2)------存储设备

上一章我们讲解了hello world 程序在计算机系统中是如何运行的. hello 程序的机器指令最初是存放在磁盘上的,当程序加载时,他们被复制到主存:当处理器运行程序的时候,指令又从主存复制到处理器.相似的,数据串"Hello World" 初始时在磁盘上,然后复制到主存,最后从主存上复制到显示设备. 从程序员的角度来看,上面的复制就是开销,减缓了程序的真正工作.因此如何将这些复制操作尽快完成则是系统设计者的一个主要目标. 1.从磁盘加载可执行文件到主存 2.将输出字符串从内存写到

深入理解计算机系统 第二章 信息的表示和处理 part2

上一周遗留问题的解决 问题:原码.反码.补码是只针对有符号数吗?无符号数有没有这三种编码方式? 得到的答案:对于无符号数,原码.反码和补码是一致的 进一步,由于有符号数是以补码的形式存储在计算机中的,而无符号数三种编码都是一致的,所以我们可以说,整型数在计算机中是以补码的形式存在的. 参考文章: https://www.jianshu.com/p/ffc97c4d2306 浮点数 对于浮点数,看了刘大的文章<看完这篇文章,你肯定理解什么是浮点数了>之后,知道了两点 1.浮点数是如何存储的 2.

深入理解计算机系统 第二章 信息的表示和处理

欣哥划重点: @所有人, 第二章比较难,我建议至少掌握下面几个知识点: 1. 字节顺序 : 大端和小端 2. 运行 图2-24, 图2-25程序 show-bytes.c 观察结果,看看有什么问题 3. 理解布尔运算,位运算 4. 理解无符号数和有符号数, 给一个数,能计算出补码 5. 理解浮点数的表示法,给一个十进制小数,能转换成二进制的浮点数表示 原文地址:https://www.cnblogs.com/stone94/p/9824395.html

《深入理解计算机系统(第三版)》第二章 信息的表示和处理

<深入理解计算机系统(第三版)>第二章 信息的表示和处理 ??计算机本身是由处理器和存储器子通过系统组成.在核心部分,我们需要方法来表示基本数据类型,比如整数和实数运算的近似值.然后,我们考虑机器级指令如何操作这样的数据,以及编译器又如何将C程序翻译成这样的指令.接下来,研究几种实现处理器的方法,帮助我们更好的了解硬件资源如何被用来执行指令.理解了编译器和机器级代码,我们就能了解如何通过编写C程序以及编译它们来最大化程序的性能.本章主要使我了解了如何表示和执行应用程序,通过一些技巧,来写出安全

深入理解计算机系统(二)--信息的表示和处理

一.信息的表示现代计算机中的信息都是使用二进制的数字进行表示,通常来说,单个的位不是非常有用,但是当把位组合在一起,再加上某种解释,就能够表示任何有限集合的元素.三种重要的数字表示:1.无符号编码基于传统的二进制表示法,表示大于或者等于零的数字. 2.补码编码表示有符号整数的最常见的方式,有符号整数就是可以为正或者为负的数字 3.浮点数编码表示实数的科学记数法的以2为基数的版本. 计算机的表示法是用有限数量的位来对一个数字编码,因此当结果太大时以至于不能表示时,某些运算就会溢出.整数运算和浮点数

《深入理解计算机系统》第六周学习笔记

第四章 处理器体系结构 (一)知识点总结 一.Y86指令集体系结构 1.Y86处理器状态类似于IA32,有8个程序寄存器: %eax.%ecx.%edx.%ebx.%esi.%edi.%esp.%ebp.处理器的每个程序寄存器存储一个字.%esp被入栈.出栈.调用和返回指令作为栈指针. 2.3个一位的条件吗:ZF.SF.OF,它们保存最近的算术或逻辑指令所造成影响的有关信息.程序计数器PC存放当前正在执行指令的地址. 3.程序状态的最后一个部分是状态码stat,它表明程序执行的总体状态 4.Y8

深入理解计算机系统(1.1)------Hello World 是如何运行的

上一篇序章我谈了谈 程序员为啥要懂底层计算机结构 ,有人赞同也有人反对,但是这并不影响 LZ 对深入理解计算机系统研究的热情.这篇博客以案例驱动的模式,通过跟踪一个简单 Hello World 程序的生命周期开始系统的学习,包括它被程序员创建,到在系统上运行,输出简单的消息,然后终止.LZ 将沿着这个程序的声明周期,先简要的介绍一些逐步出现的关键概念.专业术语以及组成部分.后面将会详细展开. 1.计算机系统 我们知道计算机系统是由硬件和软件组成的.它们共同工作来运行应用程序.虽然系统的实现方式随

计算机编程基础之深入理解计算机系统1

目录 概述——<深入理解计算机系统> 计算机系统漫游 信息的表示和处理 概述——<深入理解计算机系统> Computer Systems A Programmers Perspective  英文名 计算机系统漫游 本章简介 当系统上执行hello程序时,系统发生了什么以及为什么会这样 信息就是位+上下文 源程序(或者源文件) hello.c,实际上是由值0和1组成的位(bit)序列,8个位被组织成一组,成为字节.每个字节表示程序中某个文本字符,大部分的现代系统都使用ASCII标准