搜索
bottom↓
回复: 20

一些小经验,不同的编译器对变量初始值有不同的处理

[复制链接]

出0入0汤圆

发表于 2009-3-3 23:31:26 | 显示全部楼层 |阅读模式
好久没来,没想到论坛发生了这么不幸的事,破坏者太可恶!
最近这几天都在调试LM3S8962在uc\os-II系统下的程序,不是很顺利,给串口发数据的时候经常出现系统死掉的现象,而且是随机的,有时发一次数据就死,有时发好几次才死。每次都是死在默认的中断服务程序中,死循环,也不知道是哪个中断引起的。后来我就模仿STM32的中断程序那种格式,给每个中断都写一个单独的中断服务程序,但函数是空的,进入中断后什么都不干。结果这样做了以后,系统就不死了,不会进入不该有的死循环。
我是把数据发给串口然后回传回来,但我发现回传回来的数据字节数跟发过去的不一样,而且是随机的,很纳闷,跟踪计数数据长度的那个变量,发现每次计数的数值跟实际发送数据的长度不对,想了半天觉得可能是因为变量没有赋初始值,赋初始值以后果然一切都正常了,回传的数据和发送的一致,在一定范围内多长的数据都没关系。
不同的编译器对变量初始值有不同的处理,我记得AVR GCC里面变量默认的初始值就是0,我也一直这么用的,看来处理这些数据还是要小心一点。

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。
头像被屏蔽

出0入0汤圆

发表于 2009-3-4 01:07:08 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽

出0入0汤圆

发表于 2009-3-6 08:41:14 | 显示全部楼层
按C语言的规定,对于全局变量,静态全局变量,以及静态局部变量,如果没有初始化,则要把它们放到“ZI”(GCC称为bss),并初始化为零。但是自动变量(也就是普通的局部变量)的初值,则取决于当时栈内存中遗留的内容。

出0入0汤圆

发表于 2009-3-6 09:05:08 | 显示全部楼层
可能?要验证并确定才好哦。

出0入0汤圆

发表于 2009-3-6 09:41:35 | 显示全部楼层
补充一点。如果自动变量被优化到寄存器中,也取决于当时寄存器遗留的值。
ARMCC与GCC是符合要求的

出0入0汤圆

发表于 2009-3-6 12:38:50 | 显示全部楼层
"按C语言的规定,对于全局变量,静态全局变量,以及静态局部变量,如果没有初始化,则要把它们放到“ZI”(GCC称为bss),并初始化为零。但是自动变量(也就是普通的局部变量)的初值,则取决于当时栈内存中遗留的内容。 "

bluelucky 你好,"ZI"是一个专门放未赋值的全局变量的地方么,哪里有关于ZI的介绍。

是不是可以这么理解,C语言要求,对于没有赋初值的全局变量,编译器必须放到一个固定的段内(也就是ZI,叫“段”合适么),ZI的

地址范围是自己给出来或者要编译器自动分配,然后编译器调用库函数对ZI的地址范围进行清零操作。

是这个意思么。

印象中C51在程序开始总会加上一个清零所有RAM的(0-0x7F)的库函数。是为了遵守C的规定么。呵呵


aaa1982

出0入0汤圆

发表于 2009-3-6 13:34:02 | 显示全部楼层
c99 6.7.8 Initialization:

10 If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate. If an object that has static storage duration is not initialized explicitly,
then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively) according to these rules;
— if it is a union, the first named member is initialized (recursively) according to these
rules.

出0入0汤圆

发表于 2009-3-6 13:55:04 | 显示全部楼层
C99的spec概括起来就是:未初始化的静态存储对象一律清零。

to aaa1982:
ZI是一个特殊的段。它给出了一块内存的地址和长度,这块内存要在进入main()之前由C运行时库清零。
在程序中,所有未初始化的全局变量,所有未初始化的静态全局变量,以及所有未初始化的静态局部变量,它们所使用的内存都处在ZI段中。这三类变量,如果初始化了,则放到RW段中。RW段同样规定了起始地址和长度,但是编译器还把所有变量的初值生成一个表,然后安排记录在RO段中(也就是和代码段安排在一起),crt要执行内存拷贝操作以初始化它们。而ZI段则没有初值数据————这是显然的,因为初值约定好为零的。
    ZI段的内存需求量由编译器负责完成计算,而ZI段的起始地址则可以手工指定,但是开发工具往往给出了默认值,所以在不明白ZI段的情形下就感觉不到它的存在。
C51的实现可能在方法上另有技巧:先清零所有内存再初始化RW段,因此可能没有ZI段的概念。因为51单片机内存小,或者不想太正规吧。但是ARM下的编译器都是正规的。

出0入0汤圆

发表于 2009-3-6 20:51:07 | 显示全部楼层
感谢blueluck yyyccaa的回复。

又翻了一下谭浩强先生的书,上面就介绍了一下全局变量和局部变量分别存放在不同的内存范围内,没有提到RO,RW,ZI等的相关概念。呵呵

前一阵子看很多arm的书一讲道程序经常会说RW,RO,ZI等概念,原来以为是ARM的编译器里面给出的概念,原来是C语言对编译器的要求,学习

了。十分感谢。

aaa1982

出0入0汤圆

发表于 2009-3-7 07:26:36 | 显示全部楼层
不客气。
只读区(程序二进制代码与初始化数据),(需要初始化的)可读可写区(非自动变量),以及(归零后使用的)可读可写区是任何计算机系统中都会有的概念,只是C语言编译器给它们取了名字。前两者约定俗成的名字是RO,RW,第三者在GCC中叫.bss,在ARMCC中叫ZI——新版的ARMCC也兼容GCC语法

出0入0汤圆

发表于 2009-3-7 07:26:45 | 显示全部楼层
不客气。
只读区(程序二进制代码与初始化数据),(需要初始化的)可读可写区(非自动变量),以及(归零后使用的)可读可写区是任何计算机系统中都会有的概念,只是C语言编译器给它们取了名字。前两者约定俗成的名字是RO,RW,第三者在GCC中叫.bss,在ARMCC中叫ZI——新版的ARMCC也兼容GCC语法

出0入0汤圆

发表于 2009-3-7 10:04:27 | 显示全部楼层
感谢,学习了。
看到六楼yyccaa 引的C99关于不同类型的变量初始化的要求。(自动变量如果没有人为的初始化,则数据不确定。其他的类型变量(全局、静态)如果没有初始化,C语言要求编译器按照不同的变量类型(指针,数据,结构体,联合体)对变量进行不同方式的赋零处理)再结合楼上的解释。

是不是可以这样理解。

基本计算机系统对存储器要求分为ROM,RAM。而RAM又可以分为RW和ZI两个段(暂时按照编译器起的名字叫)

编译器要做的工作就是按照C语言的规定(该清零的清零-主要针对非局部变量又没有赋值的情况,该不管的不管-主要针对局部变量),结

合计算机系统存储器的实际情况(一般都有RO,RW,ZI),把不同的变量放到不同的段内(RW,ZI)。生成一个编译后的文件。

而编译后的文件,通过linker,结合计算机系统(一定情况下可以理解成不同处理器),把RW,ZI(当然还有RO)放到属于这些段的实际存储

器区域中。

不知道这种理解对不对?感谢赐教


一直用51,没有接触过ZI这个概念(呵呵,对计算机系统的基本组成不熟悉),51里面无论全局变量还是局部变量,最后在map文件里看都

是只有data,idata,xdata之类的区别,只是按照存储器的物理范围来分的,没有具体表示出变量到底应该属于那个段。只是最后加了一个

RELOCATION属性,全局变量都是不能重新分配的,局部变量都是可以重新分配的(如果寄存器可以解决问题,就看不到局部变量了)。

这是不是因为51资源太有限,就不按常理出牌了,呵呵



aaa1982

出0入0汤圆

发表于 2009-3-9 07:43:56 | 显示全部楼层
已经很准确了!ZI段在映像中没有数据,只包含了起始地址与长度,其它两个段还包含了各自的数据——代码与RW区的初始化值。自动变量的情况有些特殊,它的创建操作,其实只是直接把寄存器拿来用(对于优化到寄存器中的自动变量),或者对SP进行减法操作以开出栈空间后,然后使用ldr rd, [sp, #+imm]之类的指令寻址。函数返回后,寄存器就另作它用,SP也调整回去,这就体现了自动变量生命期只在函数内的原则。

寻址自动变量51有多个寻址空间,data, idata, xdata, cdata。我略看过Keil51的帮助,依稀记得它用“unique”来形容51的存储器系统,对C标准的实现变化很大。如果我没有记错,它是把局部变量也不放在栈中的,而是像静态全局变量那样处理。其它的我知道的就不多啦,反正是个另类非主流的,呵呵

出0入0汤圆

发表于 2009-3-9 20:52:48 | 显示全部楼层
bluelucky :

感谢你的解释,又学到很多东西,用了两年51了,终于要换一个,比较高兴。

另外:你说得对,51把静态变量分配到固定内存地址。

所有自动变量不能用寄存器解决的都放到一个区域,还会做所谓的overlay分析,觉得不会相互影响的会放到一个所谓的overlay区域,也就

是编译器感觉不相关的两个程序用到的自动变量可能会是一个内存地址。

如果要想把自动变量按照常规的思路放到堆栈里面,需要给该函数进行reentrant的声明,这样该函数用到的自动变量才会按照放到堆栈里面进行访问。

没想到第一个用的就是一个另类的,呵呵,还好开始接触正宗的了。

aaa1982

出0入0汤圆

发表于 2009-3-10 09:16:38 | 显示全部楼层
谢谢,恭喜升级呀!你看得比较仔细。reentrant是可重入函数,不得随意访问静态生命期的变量;overlay应该是不同函数的自动变量重叠了,需要分析哪些函数的自动变量互相重叠是安全的。计算机越弱对编译器的要求就反而越高的
你要是对C与汇编交互感兴趣,可以去ARM网站上下载"Procedure Call Standard for the ARM Architecture", "Base Platform ABI for the ARM Architecture",前者规定子程序间的调用标准,后者定义二进制可执行文件接口

出0入0汤圆

发表于 2009-3-10 11:55:19 | 显示全部楼层
感谢感谢,这就去去看看

aaa1982

出0入0汤圆

发表于 2009-3-10 12:20:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-3-10 13:20:38 | 显示全部楼层
ATPCS

出0入0汤圆

发表于 2009-3-20 14:03:27 | 显示全部楼层
又重新看了一下这篇帖子版主的解释:

不知道下面的理解对不对:

一个物理的RAM是不是可以分为RW,ZI,STACK,Heap几个部分

向版主7楼提到的,区分RW和ZI主要是因为CRT初始化的时候要针对不同的段(RW,ZI)做不同的处理。(RW放静态、全局、需要赋值的

变量,CRT初始化的时候从ROM把数据读出给RW中的数据赋值。ZI存放静态、全局、不需要赋值的变量,CRT初始化的时候就是根据ZI的开始

地址和长度把该段清零就可以了)。在实际程序运行过程中,RW和ZI存放的都是全局变量,也就是很多书上面提到的全局变量区。

stack 除了传统的保护现场,恢复现场的作用外,还有一个重要任务就是为函数中的局部(非静态)变量提供空间,在函数开始的时候调

整SP给局部变量开辟地址空间,函数结束后调整SP释放地址空间。

Heap具体就是针对动态内存的操作,具体机制还需要在看看。对于heap有一点疑问,对于Stack的操作需要硬件机制的支持(比如需要

处理器提供类似PUSH,POP的指令,还有SP这个寄存器)现在接触到的处理器(51、cortex-m3)都没有提过相关heap的指令或者寄存器,

这是不是说heap的操作对处理器有更高的要求(不知道有没有没有stack的处理器)。


又写了这么多,呵呵,希望版主和各位高手指点一下,相当感谢。

aaa1982

出0入0汤圆

发表于 2009-3-20 19:50:35 | 显示全部楼层
相当准确,基本上差不多了,恭喜啊!
RW, ZI除了放全局变量,也放静态全局变量与静态局部变量。统称为静态数据对象。
栈用于容纳没有分配到寄存器中的自动变量
栈是硬件水平上支持的内存分配模型。堆是软件水平上支持的内存分配模型,其实是把一个大数组按自己的方式切割成一个个小块。

出0入0汤圆

发表于 2009-3-20 22:49:25 | 显示全部楼层
感谢版主的指导哈,呵呵。

继续学习!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-16 17:59

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表