C语言之const

鱼鹰  鱼鹰谈单片机  2月19日

 

预计阅读时间: 5 分钟

 

我们知道,数据分为两种,一种为只读,一种为可读可写,为了防止一些不变的数据被程序意外的修改,有必要对它进行保护。这就是 const 的作用。在单片机中,不变的数据(比如代码,比如用户一些固定不变的数据)一般存放在 FLASH 中,而 FLASH 在一般情况下是只读的(事实上可以通过操作修改 FLASH,这种方式称之为 IAP ,即你可以不断更新程序的原因),而一些可变的数据一般是放在 RAM 中的,这些数据可能被指针意外的修改。所以就需要通过一种方式来将这些数据存放在 FLASH 中以防意外修改,而最好的保护就是硬件水平上的支持,这就是 const 的作用,它可以将你的数据放在 FLASH 中,但它的作用不只是如此。

 

const: 限定一个变量不允许改变,产生静态作用,const 在一定程度上可以提高程序的安全性和可靠性。

 

const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。

 

声明为 const 的变量是不能被用户改变的(意思就是说不允许你通过代码去修改这个值),因为编译器会将该变量放在只读区,比如在 KEIL 开发平台下,声明为 const 的变量放在 FLASH 区,这样即使你使用取地址符 & 获取声明为 const 变量地址,并通过指针进行修改,虽然编译器不报错,但也是无法进行修改的,因为 STM32 进行 FLASH 编程是有条件的。

 

 

你会发现虽然 p 获取了 N 的地址,但因为 N 存放在 FLAH(0x0800 0000 开始地址是 FLASH)中,所以即使通过指针的方式也是无法间接改变 N 的值的。

 

 

可以看到运行 *p = 4 的代码后,N 并没有发生改变。但是编译器确实也没报错。但是如果你直接使用 N = 4; 的话,肯定是报错的,因为你的 N 已经被申明为 const 了。

 

 

《C语言深度剖析》中关于 const 的介绍发现和 KEIL 情况不一样。    

 

 

在KEIL中进行相关代码的编写,编译,最后可以看到如下结果:

 

 

这是仿真模式下两个地址的内容,一个存放在 FLASH,一个存放在 RAM 中,并且当修改 FLAH 的内容之后(因为是软件仿真模式,可以直接修改值),复位重新运行,你会发现 RAM 的内容对应改变了(重新运行后,进入 main 函数之前,有一段拷贝代码,就是函数外申明的一些变量的初始化过程),这就说明,在 STM32、KEIL 环境下,并不是《C语言深度剖析》中说的只有一份内存,而是每一个都有一个,申明为 const 情况跟使用宏定义的方式是一样的。

 

以下是 Watch 中的内容:

 

 

但其实上面的结论是在使用 & 将 N 的地址获取后的结果(从上图可以看到 p 的值),实际上代码中如果没有获取 N 的地址时,情况又不一样了。

 

内存情况:

 

 

在删去获取 N 地址后的内存情况,可以发现 N 的值为 0x2000470,和 FLAH 地址0x08000000 一样。

 

 

这像一个地址。但通过 Memory 查看这个地址发现存放的不是 5。

 

 

根据 ARM 内核的知识可以知道,0x08000000 地址存放的其实是栈顶指针,也就是说N 存放的是栈顶指针吗?显然不是。

 

然后对 .map 地址映射文件进行搜索,你会发现,根本没有 N 的地址。这样说来, N在内存的位置对用户是不可见的,而是由编译器自动处理了。

 

那么有没有办法找到这个拷贝源头呢。之前我说过,先前能找到拷贝的源头纯属偶然,有没有什么方法可以找到呢?这其中的难点就是进入 main 函数之前的那段拷贝代码不是我们用户自己写的,而是 C 编译器自动处理的,怎么办?

 

这个时候就需要请出一个关键人物:数据观察点(关于数据观察点,将有专门的一小节详细说明,感兴趣的可以关注我)。

 

我们知道,不管如何,因为 FLASH 存放着变量初始值,然后在程序运行的时候才将FLASH 中的值初始化到 RAM 中去,也就是我们使用的 RAM 变量,那么必然存在通过总线进行数据传输的过程,所以可以通过数据观察点的功能实现对地址的监控,虽然我们不知道 FLASH 的地址,但是我们知道 RAM 的地址,所以只要对变量 i 进行监控,就可以通过内核的寄存器找到 FLASH 地址了。如下:

 

 

这里的 0x20000000 就是 i 的 RAM 地址,最终可以找到 FLASH 的位置:

 

 

由此可以知道,FLAH 中也是有多个相同副本存在的。

 

因此可以得出结论,在 STM32、KEIL 的环境下,《C语言深度剖析》对于两者的说法在这里不适用。

 

看了那么多,没有足够的基础是很难知道我在讲什么,下面用一张图进行说明,希望可以解答你的疑惑。

 

 

希望你在看完这张图之后,再回过头看看前面的那些话,对你应该会有帮助的。

 

-THE END-

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值