这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » MCU » 嵌入式C指针应用详解

共4条 1/1 1 跳转至

嵌入式C指针应用详解

工程师
2012-03-07 12:47:25     打赏
1.指针固定地址直接访问: #define rEXTINT0   (*(volatile unsigned *)0x56000088) //External interrupt control register 0 嵌入式系统编程,要求程序员能够利用C语言访问固定的内存地址。既然是个地址,那么按照C语言的语法规则,这个表示地址的量应该是指针类型。所以,知道要访问的内存地址后,比如0x56000088,    第一步是要把它强制转换为指针类型 (unsigned char *)0x56000088,s3c2410的rRTCCON是单字节访问的,所以0x56000088强制转换为指向unsigned char类型。    volatile(可变的)这个关键字说明这变量可能会被意想不到地改变,这样编译器就不会去假设这个变量的值了。这种“意想不到地改变”,不是由程序去改变,而是由硬件去改变——意想不到。    第二步,对指针变量解引用,就能操作指针所指向的地址的内容了    *(volatile unsigned char *)0x57000043    第三步,小心地把#define宏中的参数用括号括起来,这是一个很好的习惯。 (*(volatile unsigned *)0x56000088) ((void (*)(void)) (function[0]) )()功能分析 根据 Andrew Koening在他的《C 陷阱与缺陷》里对(*(void (*)( ) )0)( )的分析得到以下结论。 1.如何声明一个变量? float *g():g是一个函数,他的返回值是一个指针,该指针指向一个float数。      float (*h)(float):h是一个指针,该指针指向一个函数,这个函数的返回值是float类型的,这个函数的参数是float类型。 2.得到类型转换符。 把声明中的变量名和声明末尾的分号去掉,把剩下的作为一个整体用括号封装起来,就是一个类型转换符。 (1)float f;去掉变量名和分号,得到(float),即得到一个类型转换符 (2)float (*h)(float);去掉变量名和分号,得到(float(*)(float))这样一个类型转换符。 将(2) 中的float换成void就得到我们这里的(void (*)(void)),function[0]是一个指针数组中的一个元素,即“Test_Zdma0”,“Test_Zdma0”是一个函数名,它表示这个函数的地址,那么(void (*)(void)) (function[0])意思就是把Test——Zdma0这个地址转换成一个可以调用的函数指针。 3.调用函数指针。 假定fp是一个函数指针,那么*fp就是该指针指向的函数,那么调用它的方法就是(*fp)() 。标准C允许将上式简写为fp(),这种写法只是一种简写形式。 将fp换成上面的(void (*)(void)) (function[0])那么函数调用就得到(*((void (*)(void)) (function[0])))(),他的简写形式就是我们要分析的((void (*)(void)) (function[0]) )(). 这个语句的意思其实就是,调用Test_Zdma0()这个函数,只是把它放到数组里,何以根据自己的需要方便调用。它就是根据Andrew Koening的(*(void (*)( ) )0)( )这个语句得来的,这里的function[0]和0的意义相同。 3.二维数组与指针 从存储的角度来说,二维数组在内存中的存储,是按照先行后列依次存放的。从内存的角度看,可以这样说,二维数组其实就是一个一维数组,在内存中没有二维的概念。 如果把二维数组的每一行看成一个整体(如一个字或结构体占多个字节),即看成一个数组中的一个元素,那么整个二维数组就是一个一维数组,它以每一行作为它的元素,这个应该很好理解。 第一,我们来详细介绍二维数组与指针的关系。        首先定义个二维数组 array[3][4],p 为指向数组的指针。        若p=array[0],此时p指向的是二维数组第一行的首地址,则 p+i 将指向array[0]数组中的元素array[0]。由以上所介绍的二维数组在内存中的存储方式可知,对数组中的任一元素array[j] ,其指针的形式为:p+i*N+j (N为每一行的长度)。 元素相应的指针表示法为:*(p+i*N+j) ,下标表示法为:p[i*N+j] 。 For Example:       array[4][3]={{1,2,3},{4,5,6},{7,8,9},{10,11,12}};       int * p=array[0];       数组array有四个元素,分别为array[0],array[1],array[2],array[3],每个元素为包含3个元素的一维数组, 如array[0]的3个元素为 array[0][0],array[0][1],array[0][2]。       元素array[2][2]对应指针为:array+2*3+2,       指针表示法为:*(array+2*3+2) ,       下标表示法为:array[2*3+2] 。 特别注意:虽然 array[0] 与 array 都是数组首地址,但两者指向的对象不同,这点要非常明确。array[0] 是一维数组的名字,它指向的是一维数组array[0]的首地址,所以 *array[0]与array[0][0]为同个值。而 array 是二维数组的名字,它指向的是所属元素的首地址,其每个元素为一个行数组。它是以‘行’来作为指针移动单位的,如arraya+i 指向的是第 i 行。对 array 进行 * 运算,得到的是一维数组 array[0] 的首地址的值,所以 *array 与 array[0] 为同个值。如果定义 int* p,p为指int类型的指针,指向int 类型,而不是一个地址。故以下操作 :p=array[0] (正确) ,p=array (错误) 。这点要非常注意! 第二,看看如何用数组名作地址表示其中元素。        我们知道,对二维数组array ,array[0] 由 array指向,故*array 与array[0] 是相同的,依次类推可得 array 由array+i 指向,*(array+i) 与array是相同的。 因此,对于数组元素 array[j] ,用数组名表示为 *(*(array+i)+j) ,指向该元素的指针为 *(array+i)+j 。        注意:数组名虽然是地址,但与指向数组的指针性质不同。指针变量可以随时改变其所指向对象,而数组名不可以,一旦被定义,就不能通过赋值使其指向另外一个数组,但是在Java中则可以。 第三,顺便了解一下不太常用的‘行数组指针’。        我们知道,对于二维数组array[4][3],与int* p 。二维数组名array 不能直接赋值给p。原因前面已讲过,两者的对象性质不同。 在C语言中,我们可以通过定义一个行数组指针,使得这个指针与二维数组名具有同样的性质,实现它们之间可以直接赋值。行数组指针定义如下:   数据类型 (*指针变量名)[二维数组列数]; int (*p)[3]; 定义一个数组指针,指向的数组具有三个元素。 它表示,数组 *p 具有三个int类型元素,分别为 (*p)[0] , (*p)[1] , (*p)[2] ,即 p指向的是具有三个int类型的一维数组,也就是说,p为行指针。此时,以下运算 p=array 是正确的。当prt指向a数组的开头时,可以通过以下形式来引用a[j]: (1) *(prt+j) (2) *(*(prt+i)+j) (3)(*(prt+i))[j] (4) prt[j] 在这里,prt是个指针变量,它的值可变,而a是一个常量。



关键词: 嵌入式     指针     应用     详解     地址     这个     类型     指向         

助工
2012-03-10 16:19:30     打赏
2楼

呵呵,你稍微排一处版呀,这样看下去,要把人累坏的。
不过,还是谢谢你分享^_^


菜鸟
2012-05-10 11:06:06     打赏
3楼
呵呵 写的很好 谢谢楼主

工程师
2012-05-10 11:24:50     打赏
4楼
排了,但显示出来还是这样子,不知什么问题。

共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]