C语言中之const

版权声明:本文为博主 Osprey 原创文章,转载请联系博主! https://blog.csdn.net/weixin_42876465/article/details/84886941

const:限定一个变量不允许改变,产生静态作用,const在一定程度上可以提高程序的安全性和可靠性。
const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点。宏定义:
#define xxxx \
{
xxx
}\

\后不能有任何字符,包括空格 最后的 “}\”需要最少空一行
struct xxxx xxx = {.x1 = xxxxx,.x2 = xxxxx,.x3 = xxxxx};在C99模式下可以使用该方式对结构体进行初始化,方便观察每一个变量的初始值。
声明为const的变量是不能被用户改变的,因为编译器会将该变量放在只读区,比如在KEIL开发平台下,声明为const的变量放在FLASH区,这样即使你使用取地址符 & 获取声明为 const 变量地址,并通过指针进行修改,虽然编译器不报错,但也是无法进行修改的,因为进行FLASH编程是有条件的。
在这里插入图片描述
你会发现虽然P获取了N的地址,但因为N存放在FLAH中,所以通过指针也是无法改变N的值的。
在这里插入图片描述
可以看到N没有改变。但是编译器确实也没报错。但是如果你直接 N = 4 的话,肯定是报错的,因为你的N被申明为const。
在这里插入图片描述
《C语言深度剖析》中关于const的介绍发现和KEIL情况不一样。
在这里插入图片描述
在KEIL中进行相关代码的编写,编译,最后可以看到如下结果:
在这里插入图片描述在这里插入图片描述
(偶然巧合下才发现FLAH中也有一份拷贝,并且是RAM的复制源头)
这是仿真模式下两个地址的内容,一个存放在FLAH,一个存放在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变量,那么必然存在通过总线进行数据传输的过程,所以可以通过数据观察点的功能实现对地址的监控,虽然我们不知道FLAH的地址,但是我们知道RAM的地址,所以只要对变量i进行监控,就可以通过内核的寄存器找到FLASH地址了。如下:
在这里插入图片描述
这里的0x20000000就是i的RAM地址,最终可以找到FLASH的位置:
在这里插入图片描述
由此可以知道,FLAH中也是有多个相同副本存在的。
因此可以得出结论,在STM32、KEIL的环境下,《C语言深度剖析》对于两者的说法在这里不适用。
看了那么多,没有足够的基础是很难知道我在讲什么的,下面用一张图进行说明,希望可以解答你的疑惑。
在这里插入图片描述
希望你在看完这张图之后,再回过头看看前面的那些话,对你应该会有帮助的。
-----------------------------------------------------------------------------------2018/12/06 Osprey

欢迎关注公众号

在这里插入图片描述

没有更多推荐了,返回首页