地址绑定与“偷天换日”

指针的存储本质是 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值