3323|8

7815

帖子

56

TA的资源

裸片初长成(中级)

楼主
 

分享一个因初始化引发的奇怪问题 [复制链接]

项目到了后期,我开始一点点整理程序,把一些最初草率直接在调用处写的短函数封装成子函数。
就在这些我觉得无关紧要的改动以后,前几天我发出一个最新的测试版本,居然反馈回来一个非常奇怪的现象,在那边,主从机无法通讯!
可是我办公室这边却好好的正常工作。

为此,我翻出了好几个从前的版本,一并发过去,居然都不行,偏偏只有我上一次提交的一个版本可以。

我以为是自己这几天的修改引发的故障,从此,我开始了两天加班加点的 比照 源文件,苦不堪言。
最后迫于无奈,只好从 上一个版本开始,试着一点一点修改成 最新版本,以期定位问题出在那处改动。

这个过程非常痛苦,不仅苦了我,还苦了那位在厂子里调试的兄弟——所以事后,我说,为这事我必须请你喝酒。

最后是怎么回事呢?
事情居然如此简单,以至于我根本没想到,一直到了后来一点一点修改才发现。

从机有若干个,我们用板上的一排按键区分分机号。
所以,程序运行之初,需要读这些键去获取分机号。这个过程,是一个位一个位读,然后移位成一个8位数据,有数据确定分机号的。

——请注意 移位 这个细节,它是导致问题的关键。

当我确定了这个点以后,但我仍然对原因不甚了了。于是我决定在主循环中不断读这个分机号,我意外发现,这个过程中,这个分机号居然不断变化!!
当然,当时我仍然认为无关要紧,因为我只是在开机之初读一次键值,然后确定下来ID号就可以一直沿用。

但不管怎么说,针对这个现象都是不正常的。
过了好一阵子,我终于慢慢想明白了:

问题就出在初始化。
由于我是使用局部变量来存这个依次读键值移位合成的数据,在这里用完我就不管他了,由此我只是用了局部变量,再者,因为我觉得,用以前我就给它赋值了,所以,我无须担心初始化,也就没初始化。

问题就来了。
因为我是用 位或 的方法,把松开的键位 的 那个 1 或进来。
结果,看到了没,问题就出在我用的是位或。
如果调用函数时,这个初始值是0,那什么事情都没有,但万一它不是0,那就惨了,因为或运算对于1是无能为力的。

接下来还有一个问题:为什么,在我这边,我怎么都碰不到这个问题,偏偏在厂子里遇到了呢?

对于这一点我不确认,只是一种猜测:
我的上司经常质问我,你确定这个不初始化的变量是什么值呢?
我总是很确定的说,对于这个编译器而言是0!
是的,我敢这么说,那是因为我曾经测试过——很可惜,如果没记错,我当时测试的只是全局和静态变量,而且测的是数组。
只因为我从来没遇到过不对劲的时候所以我对这个结论没做过怀疑。

而从这个现象来看,即使在我这边,这个默认的初始值也是不确定的——否则,也就不会出现运行过程中,那个读到的ID号不断发生变化。
也就是说,这个随机值真的很随机——而过去,我一直以为,即使是随机数,也是一个固定的随机数,现在看来我犯了一个严重的错误。

而且很可能,这个默认的初始值与环境条件有一定关系。

我想,随机成一个什么样的数字,不是看硬件环境,而是看编译器的行为。

但是,连我自己都告诫自己,编译器是不可信的,隐式转换是不可信的。偏偏我还去笃信这一点。

为此,我付出了两天的时间,但因为这个原因,我回头又花了一个下午和晚上细查整个程序中的变量,并做了相应修改——并且,感觉到,很有可能,此前遗留下来的几个问题也一顺被我解决了。


----------------

说了这么多,只是想分享一个关于 初始化 的收获:
其实早在我开始学C的时候,我就牢牢记住 霍顿老头子 说的,一定要让变量是一个明确的初始值——但当时我的理解仅限于定义时赋值成0或者0xff.
然而,从昨天的查代码过程,我意识到,有时候,有些变量是不好初始化的,这个时侯就要从别的方面去确定这个初始值。

哪些变量是不好初始化的呢?比如说静态数组——你只能初始化一次,那估计最好的方式就是直接定义就初始化,可是,我们又要担心一种情况:
如果这个数组的长度有可能改变——比如宏指定,那该怎么办?
如果数组变短了好说,编译肯定会报错——有的可能还不会!!
但如果数组变长了怎么办?那就有了一些未经初始化的危险值。

对此我使用过一下两种办法:
1.我在这些地方都加了一个 #error错误检查,但这样是不现实的。
2.在函数里加一个静态标志,第一次进去,就初始化一次,然后植起该标志。
但这个仍然有点困难,最重要的是,如果这样做,除非进入该函数,不然没办法处理这些静态标志。

这个时侯也许会想到全局变量,是的,全局变量的确是个好办法。因为我们可以在开始之初用一个初始化函数一并初始化所有全局变量。
但是,昨晚回家路上,我想到了一个更综合的办法。

使用静态而不是全局,我的本意是为了限制这个变量的作用域——但其实从我考虑的角度而言意义不大,因为,如果数组越界一样会被篡改,但我仍希望限制其作用域。
所以,综合起来,那就是使用 源文件静态全局,这样,只要模块化,我还可以有一个单独的对某个子模块的初始化和结束时的处理函数。

这个说的有点多和离题了,而且我也只是想,还没付诸实践,就先说到这里。


更多的时候,需要在代码本身确保初始值。
比如说,我还遇到一个很恐怖的问题:
有一组关键数据,每次操作以前都要进行校验,一旦出错,将会把数据清零。
而我就遇到偶尔被清零的现象,当然这种现象很难察觉。只是最近在检查数据是否平才无意发现。
我在校验的子函数中,使用了一个记录错误的局部标志位——因为这个标志只需使用一次,所以我也认为无须初始化——谁让我认为它就是0!
昨晚检查时,看到这个地方我顿时倒吸一口凉气——那个现象很可能就是这里导致的。
但鉴于是一个数组不好操作,于是,我在发现错误并植起标志的地方,那是一个条件,我在出错条件以外加了一个else,就是没错时,我会直接清除该标志位,这就可以保证,这个标志不会因为初始化非零导致错误清除了。



说的有点乱了,说起来,就是,初始化绝对不只是 定义时赋值而已,而且它真的是会引发很恐怖问题的。
再次让我确信一点:隐式规则是不能过于依赖的。


此帖出自编程基础论坛

最新回复

确实我也遇到过这种问题,没初始化为0(我当时认为编译器会把它初始化为0的),但是我把这个数显示出来的时候,我发现它是有值的,之后我定义的时候每次都初始化多少写出来  详情 回复 发表于 2012-7-3 10:40
点赞 关注
个人签名

强者为尊,弱者,死无葬身之地

 

回复
举报

5

帖子

0

TA的资源

一粒金砂(中级)

沙发
 
虽然我不是弄软件的,但是还是想说,辛昕总结好认真~~
此帖出自编程基础论坛
 
 
 

回复

54

帖子

0

TA的资源

一粒金砂(高级)

板凳
 
注意到楼主比对代码用了很多时间,
有个软件推荐一下, 叫做beyond compare, 相信可以解决您不少的时间
此帖出自编程基础论坛
 
 
 

回复

7815

帖子

56

TA的资源

裸片初长成(中级)

4
 

回复 板凳 聚众 的帖子

非常感谢 聚众
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

7815

帖子

56

TA的资源

裸片初长成(中级)

5
 

回复 板凳 聚众 的帖子

额,这个是个比较软件,不知道它和ultraedit的那个文件比较器相比如何呢?
其实,花费我时间的,可能跟工具无关,而是我的比较顺序和方法有关系,加上这种事情需要小心翼翼,所以过分紧张,比照久了,经常要重复工作。
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

136

帖子

0

TA的资源

一粒金砂(中级)

6
 
楼主原来如此认真啊 !
此帖出自编程基础论坛
 
 
 

回复

44

帖子

0

TA的资源

一粒金砂(高级)

7
 
辛昕说的说这个初始化严重依赖编译器及平台,所以在移植诸如UC/OS之类的东东时,这个问题经常会出现,如果一点一点地找出哪个地方需要初始化而编译器没有做,无疑是大海捞针,(尤其是在做移植工作时),可以推荐个我自认为比较轻松的方法,上电后,写段程序,将RAM数据全部清零
此帖出自编程基础论坛
 
个人签名能力越大,责任越大;知道越多,未知更多
 
 

回复

7815

帖子

56

TA的资源

裸片初长成(中级)

8
 

回复 7楼 能圈就圈 的帖子

圈哥,主要是有时候,我要初始化成 非零 的......
比如有些标志,我的默认值不一定是0或者一样的,
比如有的0 有的0xff。。。。。

难道这是另一个不规范的问题?
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

308

帖子

0

TA的资源

纯净的硅(中级)

9
 
确实我也遇到过这种问题,没初始化为0(我当时认为编译器会把它初始化为0的),但是我把这个数显示出来的时候,我发现它是有值的,之后我定义的时候每次都初始化多少写出来
此帖出自编程基础论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表