《深入BREW开发》——第三章 编译器基础

全书地址

http://blog.csdn.net/Gemsea/category/275371.aspx 

3.3 编译器的数据处理方式
       编译器的作用是将源代码编译成可以在目标平台运行的程序,核心要处理的就是程序员所写的程序。因此,对于编译器要处理的主要程序元素有:代码、局部变量、全局变量、静态变量以及常量,概括起来就是代码和数据。如何在二进制层面组织代码和数据就是编译器需要完成的工作。通常在二进制层面存在以下三种类型的二进制数据:
       1、只读数据(RO Read Only):程序和常量
       2、可读可写数据(RW Read &Write):有初始化值的全局变量和静态变量
       3、零初始化数据(ZI Zero Initialize):无初始化值的全局变量和静态变量
       最终这些数据将会通过编译连接生成一个二进制的可执行文件,并将这些数据分别放在不同的可执行文件段(Section)中:只读数据放在text段中;可读可写数据放在data段中;另初始化数据放在bss(Block Started by Symbols)段中。接下来我们将看一看这些数据究竟是如何组织的。
3.3.1只读数据
       只读数据是我们的程序在执行的过程中不能修改的数据,开动脑筋,仔细地想一想在我们的程序中那些数据是不能修改的呢?
       第一个出现在我们脑海中的应该是那些常量。在C语言中,我们可以使用const关键字来声明一个常量。我们知道,一个变量按照其作用域可以分为全局变量和局部变量,对于一个全局的const变量来说,属于只读的数据是没有任何疑义的。但是对于一个使用const关键字的局部变量来说就有问题了,这些变量由于属于局部变量,因此在运行的时候仍然是放在堆栈中的。如果希望它变成无可争议的只读数据的话,那么我们需要同时声明这个变量为static类型的,因为在C语言中,静态变量采用了与全局变量一样的处理方式。
       除了常量之外,第二个属于只读数据的就是代码本身。代码是数据吗,有没有搞错?不要心存疑问,事实的确如此!在编译器看来,不论时变量还是代码,都属于数据。恰恰是程序中的代码是只读数据的主力军。因为在运行的时候,代码是不可改变的,所以对编译器来说,代码属于只读数据来说就不奇怪了。
3.3.2可读可写数据
       可读可写数据是指那些在代码中指定了初始化变量的全局变量和静态变量。在C语言中,全局变量属于固定分配内存的方式,需要在链接的时候就为其分配固定的存储空间。这些存储空间属于这个变量私有,从系统启动到关闭为止都只能由这个变量使用。如果一个非常量的全局变量含有初始值,那么我们就需要首先存储这些初始值,并把它们保存在我们生成的二进制可执行文件中,同时为它分配一个RAM中固定的存储空间。当我们开始执行这个可执行文件的时候,需要将这些初始值从可执行文件中复制到它所对应那段固定存储空间中。
       从某种程度上来说,可读可写的数据中的一步分需要存储在可执行文件的text区中,因为可读可写变量的初始值要存储在一个只读的空间中,在运行的时候才会复制到该变量对应的空间中。而这部分的初始值也就是只读数据的一步分了。这一点在不支持虚拟内存管理的嵌入式系统中表现得尤为突出。在采用这种方式的系统中是十分占用系统存储空间的,因为它既要占用代码段来存储初始值,而且也要占用同等的RAM空间来存储数据。
3.3.3零初始化数据
       零初始化数据就是在程序中定义的那些没有初始值的全局变量和静态变量。这些变量的特点就是固定分配存储空间,使用0做为初始化的值。这样,整个程序中零初始化变量就可以连接成为一个整片的内存区域,只需要知道地址区间,然后在初始化的时候都赋值为0就可以了。在执行程序的时候,展开ZI数据的信息,根据地址区间全部进行零初始化赋值操作。因此,零初始化数据之需要占用很少的空间来记录起始地址和结束地址就可以了。
       在嵌入式系统中,由于操作系统的代码和数据也包含在这三种类型的数据里面,因此对这三种数据的处理方式就有了很大的不同。从前面的章节中我们知道,嵌入式系统主要有CPU+ RAM+ Flash的结构,因此对于系统中的只读数据是存储在Flash中的,而RW和ZI数据则是存储在RAM中的。Flash芯片中存储的就相当于在Windows操作系统下的可执行文件(.exe),在系统启动的时候,将存储在Flash中的RW数据复制到对应的内存区域中,将ZI数据按照起始和结束地址零初始化相应的区域。
       到现在为止,细心的读者可能会发现还没有提及局部变量的处理过程,他们是存储在什么地方的?首先说明这里所说的局部变量不包含局部的静态变量,因为不管是全局静态变量还是局部静态变量全部按照全局变量方式处理。局部变量产生于函数的内部,因此它的产生和消亡也都在函数里面。在程序开始执行某一函数的时候,会为这个函数内声明的局部变量在栈内分配空间,在函数结束的时候将这些空间弹出。由此可以看出,在使用局部变量的时候要考虑栈的空间大小。由于系统中的栈主要由操作系统来管理,并且通常分配的空间是有限的(尤其是在嵌入式系统中),因此不要在函数体内使用较大的数组。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值