(嵌入式C C++语言精华 笔记3)
数据指针
在嵌入式系统的实际调试中,多借助c语言指针所具有的对绝对地址单元内容的读写能力。以指针直接操作内存多发生在
如下几种情况:
(1)某I/O芯片被定位在CPU的存储空间而非I/O空间,而且寄存器对应于某特定地址。
(2)两个CPU之间以双端口RAM通信,CPU需要在双端口RAM的特定单元(mail box)书写内容以在对方CPU产生中断。
(3)读取在ROM或FLASH的特定单元所烧录的汉字和英文字摸。
unsigned char *p = (unsigned char *) 0xF000FF00;
*p = 11;
(p++; p == 0xF000FF01;)
意义:在绝对地址0xF0000+0xFF00(80186使用16位段地址和16位偏移地址)写入11。
int *p = (int *)0xF000FF00;
p++ -----> p = p + sizeof(int);
p-- -----> p = p - sizeof(int);
注意:CPU以字节为单位编址,而C语言指针以指向的数据类型长度作自增和自减。
函数指针
理解三个问题:
(1) C语言中函数名直接对应于函数生成的指令代码在内存中的地址,因此函数名可以直接赋给指向函数的指针。
(2)调用函数实际上等同于“调转指令+参数传递处理+回归位置入栈”,本质上最核心的操作是将函数生成的目标代码的首
地址赋给CPU的PC寄存器。
(3)因为函数调用的本质是跳转到某一个地址单元的code去执行,所以可以“调用”一个根本不存在的函数实体。
《微型计算机原理》中讲到,186CPU启动后跳转至绝对地址0xFFFF0(对应 C语言指针是 0xF000FFF0, 0xF000为
段地址, 0xFFF0为段内偏移)执行,如例:
typedef void (*lpFunction) ();/*定义一个无参数,无返回类型的函数指针类型 */
/*定义一个函数指针 ,指向CPU启动后所执行第一条指令的位置*/
lpFunction lpReset = (lpFunction)0xF000FFF0;
lpReset(); /*调用函数*/
上述代码实现了“软重启”的作用。
数组 VS.动态申请
嵌入式系统中任何不经意的内存泄露都会很快导致系统的崩溃。所以一定要保证malloc和free成对出现(原则:谁申请,
就由谁释放。否则会导致代码的耦合度增大)。
内存申请原则:
(1)尽可能的选用数组,数组不能越界访问。
(2)如果使用动态申请,则申请后一定要判断是否申请成功了,并且malloc和free应成对出现。
(值结果参数,值参数)
关键字 const
const意味着只读。
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
在编译阶段需要的常数只能以#define 宏定义!
故在c语言中如下程序是非法的:
const int SIZE = 10;
char a[SIZE]; /*便宜阶段不能用到变量*/
关键字 volatile 防止编译器优化
volatile 变量可能用于如下几种情况:
(1)并行设备的硬件寄存器(如:状态寄存器)
(2)一个中断服务子程序中会访问到的非自动变量(也就是全局变量)
(3)多线程应用中被几个任务共享的变量。
CPU字长与存储器位宽不一致的处理
80186的字长为16,而NVRAM的位宽为8,在这种情况下,我们需要为NVRAM提供读写字节,字的接口,如下:
typedef usigned char BYTE;
typedef usigned int WORD;
/* 函数功能: 读NVRAM中的字节
参数:wOffset, 读取位置相对NVRAM 基地址的偏移
返回:读取到的字节值
*/
extern BYTE ReadByteNVRAM(WORD wOffset)
{
LPBYTE lpAddr = (BYTE*) (NVRAM + wOffset * 2); /* 为什么要乘2? */
return *lpAddr;
}
/* 函数功能: 读NVRAM中的字
参数:wOffset, 读取位置相对NVRAM 基地址的偏移
返回:读取到的字
*/
extern WORD ReadWordNVRAM(WORD wOffset)
{
WORD wTmp = 0;
LPBYTE lpAddr;
/* 读取高位字节*/
lpAddr = (BYTE*) (NVRAM + wOffset *2); /* 为什么要乘2? */
wTmp += (*lpAddr) *256;
/* 读取低位字节*/
lpAddr = (BYTE*)(NVRAM + (wOffset +1)*2); /* 为什么要乘2? */
wTmp += *lpAddr;
return wTmp;
}
/* 函数功能: 向NVRAM中写一个字节
参数:wOffset, 写入位置相对NVRAM 基地址的偏移
byData, 欲写入的字节
*/
extern void WriteByteNVRAM(WORD wOffset, BYTE byData)
{
......
}
/* 函数功能: 向NVRAM中写一个字
参数:wOffset, 写入位置相对NVRAM 基地址的偏移
byData, 欲写入的字
*/
extern void WriteWordNVRAM (WORD wOffset, WORD wData)
{
.......
}
_______ _________
cpu | A3--------A2 | |
80186 | A2-------A1 | |
| A1-------A0 | NVRAM |
| A0 | |
_______| |_________|
16位80186与8位NVRAM之间互连只能以地址线A1对其A0,CPU本身的A0与NVRAM不连接,因此,NVRAM的地址只能
是偶数地址,故每次以0x10为单位前进!