地址绑定与“偷天换日”

来源:互联网 发布:袁隆平 诺贝尔奖 知乎 编辑:程序博客网 时间:2024/04/30 05:53
指针的存储本质是 unsigned int 型变量。因此,我们可以将一个
指针还原为普通变量,甚至可以将一个普通整型变量强行转换为一个
指针:

unsigned int Number = 0; //普通整型变量unsigned int *p = NULL; //普通指针p = (unsigned int *)Number; //青蛙变王子Number = (unsigned int)p; //王子变青蛙
对于第一个“青蛙变王子”的表达式,我们称之为“地址绑定”。
简而言之,就是将变量 Number所代表的整数当作一个地址来看待。
至于第二个“王子变青蛙”的表达式, 嵌入式系统中除了有时候 Debug
需要,一般很少用到。显然,某一个指针所指向的实际地址数值对客
户来说没有任何意义。
地址绑定相当灵活,你可以用任何形式来给定一个整数,然后
自由地将该整数转化为任何类型的地址,甚至赋给一个指针。这里需
要明确一个概念: 地址和指针是两回事。指针中保存地址。例如,以
下各种表达式形式都是地址绑定的典型实例:

//对寄存器地址进行绑定#define GPIOR2 (*(volatile unsigned char *)0x4B)
这里,我们将常数0x4B 强制转换为一个指针变量,并通过“*
运算访问地址 0x4B。回忆前面的内容我们知道,这种方法实际定义
了一个名为 GPIOR2 volatile unsigned char型的变量。
//对指定的内存区域进行绑定float Number = 3.1415926;unsigned char *p = (unsigned char *)(&Number);
通过指针p 我们获得了存储float 型变量的4 个独立字节。这种
方法通常用于拆解数据类型、方便串行数据通信。对于 float 型变量
Number 来说,表达式首先通过“&”运算获得了该变量的存储地址;
接下来, 通过强制类型转换, 修改该地址的类型信息为 unsigned char
并将修改后的地址赋给 unsigned char 型指针变量 p。 这是一种更为常
用的地址绑定方式。
//将普通变量绑定为位段的例子typedef struct BYTE_DIV8 //一个字节拆分为 8 个二进制位{ unsigned BIT0:1; unsigned BIT1:1; unsigned BIT2:1; …… unsigned BIT7:1;}BYTE_BIT;……unsigned char Status = 0;……(*((BYTE_BIT *)(&Status))).BIT3 = 1; //通过位段将 BIT3 单独置位(*((BYTE_BIT *)(&Status))).BIT6 = 0; //通过位段将 BIT6 单独清零
在这个例子中,我们通过将一个变量的地址强行绑定在一个位
段的指针上,并通过该指针来访问位段,实现对该变量任意二进制位
的单独操作。对于 unsigned char型变量 Status,表达式首先通过“&
运算获得其地址;接下来,将这一地址的类型强行绑定为指向位域
BYTE_BIT 的指针;最后,利用“*”运算,我们就可以使用这一指针
来访问 Status 变量的任何一个二进制位了。 这种技术在嵌入式系统中
非常常见、有用,大家应该掌握并消化这一技术。

//对数组进行绑定的例子unsigned char MyZone[10];void *p = (void *)MyZone;
数组的本质,不过是一个指定大小的连续存储区域。一旦通过
声明数组的方法获得了这一区域的指针,是蒸是煮就随我们的喜好而
定了。想不想 DIY 一下动态内存分配?先用数组申请一段固定空间再
说吧。

//C 语言指针最可怕的地方,幸好 ICC 不支持此语法const unsigned int n = 1234;unsigned int *p = (unsigned int)&n;(*p) = 4321; //利用指针绕过 const 限定,修改 n 的值
看到这里, 大家应该知道为什么const 修饰的变量只能被称之为
“不应该被修改的变量”而不是“常量”了吧。只要你是变量,就有
被修改的可能,原本的“常量”竟然可以被“偷天换日”,可怕吧?
因此,这一特性甚至被作为 C 语言的一大缺陷而遭到批判。实际应用
中,这一特性在有限的范围内,是非常有用的——前提是,你知道你
正在做什么。














0 0
原创粉丝点击