《Computer Systems a Programmer’s Perspective》,机械工业出版社。中文译名《深入理解计算机系统》。作者:(美)Randal E.Bryant / David O'Hallaron

想写点推荐理由,作罢,原因是自己学识尚浅(留坑以后写?)。这里附上几个链接,也许你看过之后,也会产生和我一样的想法,阅读这本计算机界的经典著作。

以下是正文


程序的结构和执行

这是本书的第一部分,Program Structure and Execution。包括内容是第二到第六章。第二章的标题是:信息的表示和处理(Representing and Manipulating Information)

位、字、数据类型

对于有十个手指头的人类来说,使用十进制表示法是很自然的事情,但是当构造处理信息的机器时,二进制的值工作得更好。……这些微不足道的二进制数字,或者成为位(bit),奠定了数字革命的基础

现代计算机的处理、存储的信息以二进制表示。甚至可以说计算机的一切就是0和1。一个bit就是一个0或1。那为什么就偏偏是二进制而不是我们常用的十进制,或者什么三进制五进制之类?简单来说还是离散信号和模拟信号的区别。简言之,0和1这种离散值在用机器来表示时是非常方便的,例如高低电平、纸条带上孔的有无等等。而且模拟信号(如电压)有诸如很容易受其他条件干扰,很容易产生误差这样的缺点,离散数值的优势就体现了。如果说,一个单独的位,只能代表0或1,起不了多大的作用。但如果有很多的位(足够数量),并且对二进制数字串进行一定形式的编码(例如IEEE浮点规则、ASCII码等等),那么我们能赋予一串二进制数一定的意义,让其具有存储、处理信息的能力。虽然0和1是离散的,但大量的0和1,足够让我们认为是“连续”的。此时,二进制数就会向我们展示它的魔力。

十进制0~15的三种进制表示

十六进制 十进制 二进制 十六进制 十进制 二进制
0 0 0000 8 8 1000
1 1 0001 9 9 1001
2 2 0010 A 10 1010
3 3 0011 B 11 1011
4 4 0100 C 12 1100
5 5 0101 D 13 1101
6 6 0110 E 14 1110
7 7 0111 F 15 1111
  • 这张表需要熟悉,也就是要了解进制转换的一些规则。

8个bit是一个字,或者叫做字节(byte)。字节是作为最小的可寻址存储器单位(并不是一个个位去存储和访问)。每个字节都有一个唯一的数字作为标识,这个数字就是地址(Address)

计算机有一个很重要的概念叫做字长(word size),指明整数和指针的标称大小。因为一个个地址都是唯一的数字,就是由一个字编码的。所以字长决定的一个最重要的系统参数就是虚拟地址空间的最大大小。一般来说32位的计算机,限定虚拟地址空间为4GB(2的32次方减1个字节)。

C语言数据类型的字节数

大端法、小端法

测试代码如下:

#include<stdio.h>
typedef unsigned char *byte_pointer; void show_bytes(byte_pointer start, int len) {
int i;
for (i = 0; i < len; i++)
printf(" %.2x", start[i]);
printf("\n");
} void show_int(int x) {
show_bytes((byte_pointer)&x, sizeof(int));
} int main()
{
int x = 12345;
show_int(x);
return 0;
}

在显示一个w位的整数时,如果w是8的整数,那么能以字节为单位来表示。最低有效字节排在前面的方式叫做小端法,大多intel兼容机器采取小端法。大端法采用的是最高有效字节在最前面,也就是我们平常习惯的方式。例如12345的32位编码是0000 3039。小端法是如下的输出。

bool代数、逻辑运算、移位运算

bool代数

位运算

以下是一些补充记录:

  • 掩码运算。按位与:&,常用于保持某位不变(x&1),或把某些位置为0(x&0)。按位或:|,常用于将某些位置置为1(x|1)。

  • 对于逻辑运算来说,0代表“false”,所有的非0值代表“true”。

  • 对于任何值a来说,a ^ a=0,因此有(a ^ b) ^ a=b ,加以利用可以带来有趣的结果。例如:a是密钥,b是明文,a^b是加密,加密后的值就被保护。想要知道明文,只能用a去解密

  • 对于右移,<<,机器支持两种模式的右移。

    • 逻辑右移,右移后在左端补0。
    • 算术右移,右移后在左端补最高有效位的值
    • 例如 对于 x = 0x10010011,x =<< 4; 如果是逻辑右移,结果为 x = 00001001;如果为算术右移,结果为11111001。
  • 移位数量应该保持小于字长。

  • 加减法优先级比移位高。

2017/03/14 update:关于位运算符放一张很久之前整理的表格:

整数(integer)表示

整数编码

整数分为有、无符号两种类型,(unsigned)。根据字节数的不同还分为char、short、int、long、long long。

对于整数的编码,简言之,就是每个位上面的值乘以该位对应的权值,再求和。

1.无符号数编码(binary to unsigned)

  • UMax,即编码全为1。
  • UMin,编码全为0。

2.补码编码(binary to Two’s compliment),与unsigned的区别在于最高有效位解释为负权

  • TMax,符号位为0,剩下位全为1。
  • TMin,符号位为1,剩下位全为0。
  • 求一个有符号数的负数(补码的逻辑运算非),可以理解为把全部位取反后,对结果再加1。特别地,TMin的“负数”依然是TMin。

C语言默认是有符号整型。如果想要无符号常数,需要加关键词U做限制。

无符号数和有符号数之间的转换

关键点:同样字长的有符号数和无符号数,使用的是相同的位模式。

难点:C语言中,对于一个运算,如果一个运算数是有符号的,另一个是无符号的,那么C语言会隐式地将有符号参数强制类型转换成无符号数,并且假设这两个数是非负的。因此,会导致一些奇怪的结果。例如:

对于第一个式子来说,由于一个操作数是有符号,另一个操作数是无符号,那么有符号数-1被强制转换成一个无符号数,会变成一个很大的无符号数。

第二个,-2147483647-1 其实就是头文件<limit.h>中32位补码TMin的写法(这是由于C语言规则所致)。转换成无符号之后的值要比TMax大1。

第三个,这两个操作数都是有符号型,而且2147483648大于TMax,导致溢出,成了一个很小的负数。

扩展、截断

#include<stdio.h>
typedef unsigned char *byte_pointer; void show_bytes(byte_pointer start, int len) {
int i;
for (i = 0; i < len; i++)
printf(" %.2x", start[i]);
printf("\n");
} void show_int(int x) {
show_bytes((byte_pointer)&x, sizeof(int));
} void show_short(short x) {
show_bytes((byte_pointer)&x, sizeof(short));
} int main()
{
//扩展
short x = 12345;
show_short(x);
printf("short x = %d\n", x);
show_int(x);
printf("int x = %d\n\n", (int)x); //截断
int y = 123456;
show_int(y);
printf("int y = %d\n", y);
show_short(y);
printf("short y = %d\n\n", (short)y);
return 0;
}

扩展,例如short到int,int到long long int这样。不会改变数字的值。如果是无符号数就是扩展全部为0的位,有符号数就是扩展全部为1的位。

截断,例如int到short,有点类似于右移,类似于mod 2的n次方,但只是类似。对于大的数据,截断会导致溢出。例如int型整数123456大于short能表示的最大数值范围,如果将其截断会导致上溢出从而得到一个负数。

2017/03/14 update:如果打算通过使用扩展位数的手段来使得一些运算结果由原本的溢出变为不溢出,那么强制类型转换和计算这两个过程的先后顺序很重要。例如下面这个函数验证两个32位的int型整数做乘法有没有产生溢出,验证的手段是先用64位的整型存结果,再将64位乘积截断为32位是否会改变其值:

int imull(int x, int y){
long long pll = (long long)x * y;
return pll == (int)pll;
}

代码第二行的强制类型转换至关重要,先转换再计算。如果第二行是这么写的话:

long long pll = x * y;

那么会用32位值来计算乘积(可能这会溢出),然后再将其扩展为64位。显然不会达到目的。可以参考下面的运行结果


See Also

部分公式、数据截图来源

【CSAPP笔记】1. 位、字节、整型的更多相关文章

  1. 面试问题2:给一个5G的大文件,保存的数据为32位的整型,找到所有出现次数超过两次的数字

    问题描述:给一个5G的大文件,保存的数据为32位的整型,找到所有出现次数超过两次的数字 大数据操作: 解决方法一: 依次遍历文件数据, 开始32二进制清0 每次读取一个数,先和二进制位与,如果为0 则 ...

  2. 编译器是如何实现32位整型的常量整数除法优化的?[C/C++]

    引子 在我之前的一篇文章[ ThoughtWorks代码挑战——FizzBuzzWhizz游戏 通用高速版(C/C++ & C#) ]里曾经提到过编译器在处理除数为常数的除法时,是有优化的,今 ...

  3. C/C++的64位整型

    在C/C++中,64为整型一直是一种没有确定规范的数据类型.现今主流的编译器中,对64为整型的支持也是标准不一,形态各异.一般来说,64位整型的定义方式有long long和__int64两种(VC还 ...

  4. C++64位整型

    今天在Ubuntu下编译C++代码,然后毫无防备的出现以下错误: 查阅了相关资料,__int64是VC++独有的,因此64位g++无法识别. 以下内容转载自:Byvoid 在C/C++中,64位整型一 ...

  5. C++将整型数据转换成大端或小端存储顺序

    大端和小端的概念参考之前博客: 大端/小端,高字节/低字节,高地址/低地址,移位运算 昨晚帮导师从指令中恢复图像的时候,导师要我转换成raw格式,也就是记录图像像素的二进制序列,然后反复强调让我注意大 ...

  6. GO语言学习——基本数据类型——整型、浮点型、复数、布尔值、fmt占位符

    基本数据类型 整型 整型分为以下两个大类: 按长度分为:int8.int16.int32.int64 对应的无符号整型:uint8.uint16.uint32.uint64 其中,uint8就是我们熟 ...

  7. 【CSAPP笔记】2. 整型运算

    现在想补补推荐这本书的理由. Most books on systems-computer architecture, compilers, operating systems, and networ ...

  8. Linux漏洞分析入门笔记-CVE_2018_6323_整型溢出

    操作系统   Ubuntu 16.04 /32 位 调试器     IDA pro 7.0 漏洞软件   binutils-2.29.1 0x00: 漏洞描述 1.什么是整数溢出: 在计算机中,整数分 ...

  9. Python入门篇-基础数据类型之整型(int),字符串(str),字节(bytes),列表(list)和切片(slice)

    Python入门篇-基础数据类型之整型(int),字符串(str),字节(bytes),列表(list)和切片(slice) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Py ...

随机推荐

  1. Hadoop(18)-MapReduce框架原理-WritableComparable排序和GroupingComparator分组

    1.排序概述 2.排序分类 3.WritableComparable案例 这个文件,是大数据-Hadoop生态(12)-Hadoop序列化和源码追踪的输出文件,可以看到,文件根据key,也就是手机号进 ...

  2. iOS Swift WisdomHUD 提示界面框架

    iOS Swift WisdomHUD 提示界面框架  Framework Use profile(应用简介) 一:WisdomHUD简介 今天给大家介绍一款iOS的界面显示器:WisdomHUD,W ...

  3. Scala基础语言api入门学习

    Scala的变量定义 变量定义 声明一个val变量类似与java的 public static final String 一致,一旦初始化不能改变,和java的泛型类似,Scala会帮我们进行类型推断 ...

  4. 20145209刘一阳《JAVA程序设计》第二周课堂测试

    第二周课堂测试 1.if关键字后面的小括号内,表达式的值可以为10.(B) A .true B .false 2.表达式0xaa | 0x55的值为(C) A .FF B .0 C .255 D .1 ...

  5. 微信小程序的经纬度不想写死,需要转成number类型不能用浮点型

    click: function (e) { var msg = this.data.placeData; var latitude = Number(msg.latitude) var longitu ...

  6. [Qt扒手2] PyQt5 路径绘画例子

    [说明] 此例扒自 Qt 官网,原例是 C++ 代码,我把它改写成了 Python + PyQt5 版本. 有了前一个例子的成功,这个例子改写的非常之快.记得第一个例子花了我几天的时间,而这个例子只花 ...

  7. 3、计数排序,电影top100

    1.计数排序 # -*- coding: utf-8 -*- # @Time : 2018/07/31 0031 11:32 # @Author : Venicid def count_sort(li ...

  8. OpenStack入门篇(十九)之网络虚拟化基础

    1.Linux Bridge的基本概念 假设宿主机有 1 块与外网连接的物理网卡 eth0,上面跑了 1 个虚机 VM1,现在有个问题是: 如何让 VM1 能够访问外网?① 给 VM1 分配一个虚拟网 ...

  9. Windows:打开MSDTC,恢复Windows任务栏,查看windows日志,打开远程桌面,打开Services,资源监控

    Windows 服务器系列: Windows:查看IP地址,IP地址对应的机器名,占用的端口,以及占用该端口的应用程 Windows:使用Dos命令管理服务(Services) Windows:任务调 ...

  10. nginx 部署前期一定要关闭selinux

    nginx 报错: 1389#1389: *40 "/home/data1/index.html" is forbidden (13: Permission denied), cl ...