一个黑客对C指针的认识

Fom:邪恶八进制
一、指针的概念

  我们应该这样理解程序代码:一种可以被机器解释执行的数据。那么,我们就可以用统一的观点来看待程序与数据,并将之与指针关联起来。

  运行时数据总是要存储在内存中的,以备CPU的不时之需。为了能够有效地访问数据,计算机系统势必要对内部存储单元进行编号--就像门牌号一样。有了明确的编号,总线控制器就得以快速而准确地定位并访问内存,顺利地将数据提取出来。在这里,"内存编号"起到了一种指示地址的作用。可以这样说,任何存在于内存中的东西(啊,啊,都是些逻辑上的0、1代码串)都拥有地址,以便于对其进行访问。

  注意唷,"内存编号"这样的东东只存在于逻辑空间内,在物理空间中则是用电路线来映射编号的:)。

  事实上,这种"内存编号",或者简称"地址",本身也是一种数据--毕竟它的数据类型可以视为unsigned integer,当然能保存在内存中(废人语:这是丫指针的本质)。但是,这种数据有点特殊:它被用于指示别的数据的地址,所以保存它的内存单元对应的变量类型也比较特殊:指针类型。顾名思义,指针就是一种"其值具有指向性"的变量。看起来颇简单吧?但,越是简单的东西麻烦就越是多,比如……

  指针具有两个属性,一个是它的值(就是地址),一个是它的类型(数据类型)。花开两枝,各表一头,咱们先来说说"地址"的"值"。地址值是有大小范围的,其上下限是[0,2^n),即从"0"到"2的n次幂减1",其中n是机器地址线的数量。通常这个n值不会与CPU的字长一致,但实际使用地址值时n都会取CPU字长为基准(这个问题另外撰文指出原因)。在不同的硬件平台上,指针变量占用的内存单元数量与其地址值的范围大小成正比,也即指针变量占用n个内存位(bit)。

  在数学中"零"是一个很特殊的值,而值为零的地址也是一个特殊的地址。它于用指示地址为零的内存单元--废话--但是操作系统一般会把拥有零地址的内存区域划为安全区,且只用作捕获越界指针使用。因此将一个指针初始化为零地址是非常安全,而且是非常必要的(在C的某些编译器中一定要对指针进行初始化才能使用)。一般而言,我们不必在意地址的确切值是多少,也不用在意这个地址的种类是什么(实地址,虚地址,物理地址,逻辑地址……),把一切都扔给编译器去完成好了,毕竟人脑不是编译器:)。

  指针的另一个属性是数据类型。实际上这个类型是指针指向的变量的数据类型,而不是指针自身的类型。因为指针的类型是所谓的"用户定义类型"而不是"编译器内建类型"。这个类型有两个作用:1)指示编译器在进行解引用的时候应该从内存中获取几个字节(就是数据类型对应的内存单元占用数,单位是字节Byte),2)以及指示编译器在进行指针类型转换时如何进行类型检查与类型匹配。

  通常来说同一个地址值可以搭配不同的数据类型(只要逻辑上说得通),这样通过指针就可以获取位于同一块内存区域中的不同类型的数据(换言之,是把同一块内存中的0、1代码串解释成不同类型的数据),这就是1)中所说的指针的作用。举个例子:

  int a = 0xFF00;

  char *p = (char *)&a;   // 强制类型转换,确保类型匹配(第二点作用的体现,以通过类型检查)

  cout << *p << endl;   // 指示编译器只获取一个字节数值(第一点作用的体现,以取出正确的数据)

  运行结果是0,即只取出了低十六进制位一个字节的数值。

  以上是关于指针专题的前导性知识,希望大家踊跃拍砖。
上一篇:
下一篇: 学C++时要注意的
字母检索 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z