||
蚂蚁注解:
"指针是用来存放地址的,指针变量的长度就是其所在机器地址总线的长度", 这句并不适用所有CPU,如采用哈佛结构的CPU,程序和数据具有单独的总线和存储空间,在某些型号中,程序总线与数据总线并不相同,在这类CPU中,不同类型的指针变量具有不同的长度。
即使同为指向数据空间的指针变量,其长度也不全部相同。有些MCU将其RAM分成多个Page,这样定义于某个Page内的指针变量与定义在全部RAM区的指针变量具有不同的长度。
原文:
似乎C语言的指针是个人们永远都讨论不完的话题,无论是初学者还是老手。那么下面简单说说我对指针的一些浅薄的理解。
需要首先明确的是C语言中的指针是一种数据类型,单从这点上来看,指针和int,float什么的没什么大区别,但是指针这种数据类型所存储的东西可就大有讲究了。
我们都清楚,程序是要在内存中执行的,在内存中执行的话就必须得有个确认位置的方法,这个方法就是内存的地址。也就是说,一个运行中的程序中的所有的“部件”(指令,数据什么的),都在内存中放着呢,也就是他们都有地址。那么指针呢,就是专门用来存放这些内存地址的一种变量。因为它存放的值是地址,这就导致了指针变量和其他类型变量有很大的不同。
指针具有两大特点,一是指针变量本身的值。这个值刚才说了,就是别的数据的地址(变量)或者指令的地址(函数),这个地址可以理解为一种间接访问他人的“线索”,也就是说,通过指针变量中存放的地址,可以访问某些数据或者实现指令的跳转。既然是变量,那肯定有自己存储空间的大小了。那么指针变量的大小是多少呢?这个非常简单:指针是用来存放地址的,那么指针变量的长度当然就是其所在机器地址总线的长度了!比如在32位的x86上,指针一般来说就是32位的,也就是4个字节大小。二就是指针变量的类型。我们都知道再声明指针变量的时候都得指名类型,比如char */int *等,那么这里的char/int之类的又有什么含义呢?我认为可以把这些类型理解成一种“尺度”,或者说是一种“权限”。如刚才所说,指针的值指明了可以访问的位置,那么指针的类型则限制了指针从该位置所能访问的长度。比如,
int *p 说明了p这个指针变量在使用诸如*p等方式访问p中存放的地址中的数据的时候,系统会提取sizeof(int)长度的数据出来,这个数据当然就是一个int型的值了,或者在进行诸如p++这样的操作时,系统会加上sizeof(int)的长度。总而言之,指针其实就是一个地址加一个长度,地址限定了指针起始的位置,而长度则规定了系统按什么方式来解析内存的数据。
有了以上的说明,下面将要唠叨的有关于指针强制类型转换的概念就很好理解了
指针的强制类型转换很好理解,转换的就是指针的类型,也就是系统使用指针的方式。比如从int*转换到char*,那么指针中的地址并没有变化,只是类型变了,比如在执行p++的时候,原来是增加4个字节(32位int),而转换之后便成了增加1个字节(char的长度)。再复杂一点,常规类型向结构体的强制类型转换也是这样的道理。在Linux的网络编程中常常用到将某种指针强制转换成某种协议包头的struct,然后提取该包头的数据(由于最近小研究了一下pcap,对这个比较熟悉^_^)或者各种结构体的指针之间进行类型转换。这些转换其实都是在改变系统对从某一地址开始的一堆数据的不同的解释方法。比如在pcap中,抓取的以太网数据包(当然在内存中存在)的地址被存放到了一个u_char类型的指针中,这个指针其实就是一个存有整个数据包所有信息的一块内存空间的开始地址!但是如果使用char类型的指针来一个字节一个字节的访问该内存段当然无法取得正确的数据,所以要把u_char转换成相应的网络协议的struct,然后按顺序访问,具体就不赘述了。类似的例子还有很多,但我认为如果仔细研究一下pcap库提取数据的方式,会对指针强制类型转换的理解有很大的帮助。
总之呢,指针也并非什么神秘之物,也没有人们说的那么难懂,关键就是一个地址的问题。我倒是认为C语言最闪光,最强大,最灵活的特性就是指针了。指针,C之魂也~!