信息存储
大多数计算机使用8位的块,或者字节,作为最小的可寻址的内存单位,而不是访问内存中单独的位,机器级程序都将内存视为一个非常大的字节数组,称为虚拟内存,顾名思义,这个虚拟地址空间只是一个展示给机器程序的概念性映像,他与我们硬件上的物理内存是有区别但是又存在一定联系,我们将在之后的章节里面详细讨论。
编译器和运行时系统是将存储器空间划分为更可管理的单元,来存放不同的程序对象(program object),即程序数据、指令和控制信息。可以用各种机制来分配和管理程序不同部分的存储。这种管理完全是虚拟空间里完成的。例如,C语言中一个指针的值(无论它指向一个整数、一个结构或是某个其他程序对象)都是某个存储块的第一个字节的虚拟地址。C编译器还把每个指针和类型信息联系起来,这样就可以根据指针值的类型,生成不同的机器级代码来访问存储在指针所指向位置处的值。尽管C编译器维护着这个类型信息,但是它生成的实际机器级程序并不包含关于数据类型的信息。每个程序对象可以简单地视为一个字节块,而程序本身就是一个字节序列。
十六进制表示法
基本概念
十六进制(简写"HEX"),是使用数字 0 ~ 9
以及字符A ~ F
来表示16个可能的值,下图为十六进制数与二进制数和十进制数之间的对应关系
在C语言中,以0x
或0X
开头的数字常量被认为是十六进制的值。字符‘A’ ~ ‘F’
既可以是大写,也可以是小写,甚至是大小写混合。例如,我们可以将十六进制数字FA1D37B
,写作0xFA1D37B
,或者0xfa1d37b
,0xFa1D37b
。
进制转换
十六进制与二进制
对于十六进制转换二进制,我们可以将十六进制的每一位展开转换为2进制,如下图
对于一个二进制数,首先要把他分成每4位一组来转换为十六进制,要注意的是,如果总位数不是4的倍数,那最左边的一组可以少于四位,前面补0,然后将每个4位组转换为对应的十六进制数
小技巧
十六进制与十进制
字数据大小
寻址和字节顺序
对于跨越多字节的程序对象,我们必须建立两个规则:这个对象的地址是什么,以及在内存中如何排列这些字节。**在几乎所有的机器上,多字节对象都被存储为连续的字节序列,对象的地址为所使用字节中最小的地址。**例如,假设一个类型为int的变量x的地址为0x100
,也就是说,地址表达式&x的值为0x100
。那么,(假设数据类型int为32位表示)x的4个字节将被存储在内存的0x100
、0x101
、0x102
和0x103
位置。
某些机器选择在内存中按照数据的低位到高位依次从内存的最低有效字节到最高有效字节的顺序存储,而另一些机器则按照从数据的低位到高位依次从内存的最高有效字节到最低有效字节的顺序存储。前一种规则称为小端法(littleendian)。后―种规则称为大端法(big endian)。
判断当前机器使用的是大端法还是小端法
原理
代码
void CheckEndian(int* x)
{
char* p = (char*)x;
if (*p == 1)
printf("小端存储\n");
else
printf("大端存储\n");
}
int main()
{
int x = 1;
CheckEndian(&x);
return 0;
}
布尔代数简介
将逻辑值TRUE(真)和假(FALSE)编码为二进制值1和0,用来研究逻辑推理
布尔运算~
对应于逻辑运算NOT
布尔运算&
对应于逻辑运算AND
布尔运算|
对应于逻辑运算OR
布尔运算^
对应于逻辑运算⊕(异或)
我们可以将上述4个布尔运算扩展到位向量的运算,位向量就是固定长度为w、由0和1组成的串。位向量的运算可以定义成参数的每个对应元素之间的运算。
C语言中的位级运算
C语言中的逻辑运算
短路特性:逻辑运算符&&
和||
与它们对应的位级运算&
和|
之间第二个重要的区别是,如果对第一个参数求值就能确定表达式的结果,那么逻辑运算符就不会对第二个参数求值。
C语言中的位移运算
C语言标准并没有明确定义对于有符号数应该使用哪种类型的右移,算术右移或者逻辑右移都可以。这就意味着任何假设一种或者另一种右移形式的代码都可能会遇到可移植性问题。然而,实际上,几乎所有的编译器/机器组合都对有符号数使用算术右移,且许多程序员也都假设机器会使用这种右移。另一方面,对于无符号数,右移必须是逻辑的。
与C相比,Java对于如何进行右移有明确的定义。表达是x>>k会将x算术右移k个位置,而x>>>k会对x做逻辑右移。