当前位置: 首页 > 文档资料 > C 语言程序设计 >

C语言只读空间

优质
小牛编辑
148浏览
2023-12-01

我们现在看向内存中的只读数据段和代码段构成的只读空间的概念。

代码段

当程序越来越多,代码段也就越来越大。代码段里面的代码是不可以在运行的时候被修改的,在编译的时候就已经定格了。如果我们试图去写它,就一定会出现段错误。

测试代码如下

我们定义了一个unsigned char类型的指针去指向main函数的地址,强制转换之后告诉编译器我们需要用这样方式读取。在获取到main函数地址之后,我们对这个字节的内容进行读取;然后再将它的值试图修改,然后再输出。

运行结果如下

我们成功的访问到了main函数的地址里面的数据,但是在试图修改它的值的时候,编译器报出了一个段错误。一旦我们操作代码段,操作系统就会认为程序是非法程序,然后将程序关闭掉。

只读数据段

下面就是一个关于只读数据段的一个经典错误:

测试代码如下

p1是一个普通的指针变量,但是它指向的却是一个常量字符串,这个字符串就保存在只读数据段中,它首先将这个字符串输出了。在第二个打印函数中,我们打印的是一个字符串“Hello world”的地址,这样可以看出它存储的段。再下面我们试图通过可变的指针去修改常量段的数据。

运行结果如下:

打印了这个字符串,还获取到了常量字符串的首地址,可以看到和我们的代码段相隔很近。我们修改常量段导致了一个段错误。

除了只读空间和内核空间以外,其它的空间就是一个可读可写的空间。如果我们定义了一个const int a=10;通过一个指针去修改它,a的值是可以被修改的。因为a是一个局部变量,系统不会将它放在只读数据段中,会将它放在局部变量中,这就是C的定义方式。

我们可以通过size build命令查看各个段中的大小。红色方框中为静态的数据段,程序在运行之前就被打包在那里。在汇编之后生成了一堆原材料,将这些原材料打包成一个可运行程序,将这些数据分别放到这三个段中(代码段(TEXT),只读数据段(TEXT),全局的数据空间(data和bss)。

我们在其中一个输出字符串的前面加了1234,由于他们是字符串,所以它们应该比原来多了4个字节。(为什么我们没有修改第一个输出字符串the p1 is,是因为下面还有一个输出相同的字符串,可能会因为编译器的优化导致代码段的优化保存,就不是添加四个字符了。)

运行结果如下

我们可以看到前后之间的区别,text段的数据多了四个字节,是因为我们添加了四个字符的结果。

对于我们嵌入式开发而言,这个程序的代码段就不能太大。比如路由器,它的成本比较低,flash存储器非常小,只有一两兆,如果我们的Text太多,占据了太多的空间,那么就显得太多余臃肿。所以最终生成的Release版本的程序有些打印信息是要去掉的。我们在实际工程中,debug版本是无所谓的,但是Release版本我们就需要对一些字符串进行裁剪,减小可执行程序代码的大小,尤其是嵌入式模板开发中,这个非常关键。