1 信息存储
机器级程序将内存视为一个非常大的字节数组,成为虚拟内存(virtual memory)。内存的每个字节都由唯一的数字来标识,称为它的地址(address),所有可能的地址集合就称为虚拟地址空间(virtual address space)。每个程序对象可以简单地视为一个字节块,而程序本身就是一个字节序列。
1.1 十六进制
十六进制(hexadecimal)数(简写为hex),使用'0'~'9'和'A'~'F'表示十六个可能的值。
需要注意的情况:
1.在C语言中,以0x或0X开头的数字常量被认为是十六进制的值。
2.字符'A'~'F'既可以是大写,也可以是小写,甚至可以混合。
3.十六进制和二进制转换:二进制每四位分一组,十六进制每个字符代表四位二进制数字。
1.2 字数据大小
每台计算机都有一个字长(word size),指明指针数据的标称大小(nominal size)。对于一个字长为w位的机器而言,虚拟地址的范围为0~2w-1,程序最多访问2w个字节。
例如,32位字长限制虚拟地址为4千兆字节(4GB)。扩展到64位字节使得虚拟地址空间为16EB,大约是1.84×1019字节。
一些32位程序和64位程序上占有不同字节的数据类型:1.long和unsigned long:4/8 2.指针类型:4/8 3. int32_t:4个字节 int64_t:8个字节。
1.3 寻址和字节顺序
排列表示一个对象的字节有两个通用的规则:(以x的类型为int,位于地址0x100处,它的十六进制为0X01234567)。
1.大多数Intel兼容机、Android和iOS操作系统选择在内存中按照从最低有效字节到最高有效字节的顺序存储对象,称为小端法。
地址 | 0x100 | 0x101 | 0x102 | 0x103 |
... | 01 | 23 | 45 | 67 |
2.IBM和Oracle的大多数机器则是将最高有效字节存储在最前面,称为大端法。
地址 | 0x100 | 0x101 | 0x102 | 0x103 |
... | 67 | 45 | 23 | 01 |
1.4 表示字符串:ASCII字符码和Unicode文字编码标准
在使用ASCII码作为字符码的任何系统上都将得到相同的结果,与字节顺序和字大小规则无关:文本数据比二进制数据具有更强的平台独立性。
UTF-8表示将每个字符编码为一个字节序列,意味着所有的ASCII字节序列用ASCII码表示和用UTF-8表示是一样的。Java编程语言使用Unicode来表示字符串。
1.5 表示代码
不同的机器类型使用不同的且不兼容的指令和编码方式,即便是完全一样的进程,运行在不同的操作系统上也会有不同的编码规则,因此二进制代码是不兼容的。二进制代码很少能在不同机器和操作系统组合之间移植。
从机器的角度看,程序仅仅是字节序列。除了可能有些用来帮助调试的辅助表以外,机器没有任何关于原始源程序的任何信息。
1.6 布尔代数简介
单目运算符:~非。
双目运算符:&和 |或 ˆ异或
额外内容:布尔代数和布尔环:
&对|的分配律:a&(b|c)=(a&b)|(a&c)
|对&的分配律:a|(b&c)=(a|b)&(a|c)
考虑到位向量上的ˆ、&和~运算,构成布尔环:此时扮演整数运算中加法角色的是ˆ,
每个元素的加法逆元是它本身:aˆa=0,且满足加法的交换律:(aˆb)ˆb=b。
1.7 C语言中的位级运算、逻辑运算和移位运算
位级运算:|、&、~和ˆ 应用:掩码运算(使用&符号实现对特定位的清除、使用~0生成二进制表示全为1的掩码)。
逻辑运算:||、&&和!,返回值为0或1;
移位运算:<<、>>和>>>:(左结合)
x<<k:左移位,向左移动k位,舍弃最高的k位,并在右端补0;
x>>k:1.逻辑右移:舍弃最低的k位,在左端补上k个0;(在Java中>>严格代表算数右移)
2.算术右移:舍弃最低的k位,在左端补上k个最高有效位的值;
x>>>k:Java中独有的逻辑右移(与Java中的>>相比较)
2 整数表示
本节所使用的缩写:
B:二进制(Binary) U:无符号数(Unsigned) O:反码(One's complement) S:原码(Sign-Magnitude) T:补码(Two's-complement)
X2YW:w位数、X类型的数据转化为Y类型 +wX:w位、X类型的加法(乘法以此类推,一般省略w下标)
w位的整数数据类型x,位向量x:
2.1 整型数据类型
C语言支持多种整型数据类型,除无符号数之外,一个值得关注的特点是取值范围是不对称的——负数的范围比正数的范围大1。
C语言标准定义了每种数据类型必须能够表示的最小的取值范围。除了int_32和int_64之外,其他类型均规定正数和负数的取值范围是对称的,而有些类型比规定的要小一些,例如:int可以用两个字节来实现(-32767~32767),几乎回退到了16位机器的时代。
Ps:C和C++都支持有符号和无符号数,Java只支持有符号数。
2.2 无符号数的编码
无符号数编码是唯一的。
2.3 补码编码
补码用于表示负数值,最常见的就是补码形式。在这个定义中,将字的最高有效位解释为负权(negative weight)。
最高有效位xw-1也称为符号位,它的“权重”为-2w-1,是无符号表示中权重的负数。
补码编码是唯一的。
2.4 有符号数的其他表示方法
反码:除了最高有效位的权是-(2w-1-1)而不是-2w-1,其余和补码一样:
原码:最高有效位是符号位,用来确定剩下的位应该取负权还是正权:
2.5 原码、反码、补码的数学关系
对于正数而言,原码=反码=补码
对于负数而言,反码=原码除符号位取反,补码=反码+1。
2.6 有符号数和无符号数之间的转换
补码转换为无符号数:
无符号数转换为补码:
2.7 C语言中的有符号数和无符号数的转换
进行强制类型转换时,保持位值不变,只是改变了解释这些位的方式。
当执行一个运算时,如果它的运算数一个有符号一个无符号,那么C语言将隐式地将有符号数转换为无符号数,并假设这两个数都是非负的。
有时需要注意补码的不对称性与C语言转换方式规则的交互。
2.8 扩展一个数字的位表示
可以证明,无符号数的位扩展是在前面的位补0,称之为零扩展(zero extension)。
此外,补码的位扩展是在前面的位补原最高有效位的数,称为符号扩展(sign extension)。
2.9 截断数字
无论是截断无符号数还是截断补码数值,设原位向量为x,x‘是截断为k位的结果,均有:
标签:表示,CSAPP,字节,符号,二进制,补码,信息,C语言,第二章 From: https://www.cnblogs.com/zekang666/p/17992363