All Stories

同样的操作,三处代码错误

  今天下决心修改一个崩溃的问题,只要快速打开多个文件,再通过菜单“关闭所有”窗口时,就会崩溃,通过一次又一次的崩溃实验,分析每一次的dump记录,居然意外地发现每次崩溃最后的堆栈信息都不一样,总共有三处代码。  把这三处代码仔细推敲之后,发现确实有可能引起崩溃的原因,而这样的代码如果让我仅仅是通过正常的审视,是绝对看不出什么问题来的。修改完这三处代码,再实现,又暴露出另外一个崩溃的问题,也是那些代码附近,真是汗颜啊!

想起那些人

  早上听同事说起,那个杰克逊死了。当时还没什么特别的想法,心想也就一个出名的歌手吧,死就死吧。  下午小妞发来一个mp3,名字是《Heal the World》,很好听。突然想起初中时班上一个转学生,一个身材纤细,特长舞蹈的女生,据说她的偶像就是杰克逊。那是我第一次知道有杰克逊这么个人,看到那CD封面上的照片,心中一点都不感冒,尤其不能接受他那种打扮。心中还纳闷为什么这么一个清纯的小姑娘会把这样的人当成偶像。那个女生后来在初三最后一个学期又转学了,大概因为户口之类的原因需要回原籍去中考,再后来就一直没见过了。记得在我在高一的时候,那段混乱而手足无措的日子,还偶尔听到过一两个男生在那里对她的yy,那时我只觉得这太假了,虚伪得太明显了。  春去秋来,不知道那些曾经从身边经过的人,现在都在哪里,过着怎样的生活……

sqlite3的Blob操作,变异……

  本来想当成二进制数据一样把文本内容以Blob形式存入Sqlite3的,结果整了半天,虽然最后存是存进去了,好像不是像我预想中的那样写二进制的Blob,而是就是作为文本存入了。不过倒是知道了对于大块数据的操作,在简单的SQL语句中不能方便地实现时,可以用sqlite3_bind系列API,在SQL语句中可以用问号作为占位符,然后将数据bind到各个占位符上去。这样一来的SQL语句要用statement来执行。  存进去后,取出来也是一个问题,本来以为Blob么,二进制么,还专门从别处移植了一段代码过来,结果那段代码可能有点点问题。反正最后我也是看出来了,因为我是原样照搬地把数据存入的,那么还是原样取出来就行了,我大汗!真不知道如果哪天我真要存入一段二进制数据时,应该怎么办了!大概,存入的方式也要跟着改吧。

在CI中使用bjam构建项目

  不知道什么原因,我的机器上什么VC2008命令行来编译项目,无论是devenv.com还是devenv.exe,都会占满CPU,而真正的编译进程cl.exe却一直慢吞吞地,几个文件的小项目,也不知要等上多少时间,在持续集成时实在忍无可忍。  不过因为之前有一段时间专门学习了一下如何使用bjam,所以我就决定在CI上,使用bjam来构建项目。统计了一下我的项目的情况,有用MFC的,有用WTL的,也有用wxWidgets的,有用VC编译的,也有用MinGW编译的,无论哪种情况,bjam都可以满足需求。  使用bjam的一个比较方便的特性是,它能比较智能地自动为不同的编译器套件使用各自的命令行编译选项,这样使得一个bjam脚本可以同时不同的编译器套件来编译。不过实际使用过程中,还是有些需要区别对待的地方,这可能是因为bjam主要用于boost的构建这个目的而产生吧。  比如对于VC和MinGW,可能链接的库文件是不同的,要么是文件名不同,要么是所在路径不同;链接选项可能不同,也许是boost的原因,bjam在构造exe时,默认是使用控制台子系统,所以需要自己在链接选项中自行指定使用Windows子系统,而该选项在VC和GCC中有细小的描述上的区别。  bjam的另一个比较方便的特性是,它能自动寻找编译器套件默认的头文件路径和库文件路径。这比使用makefile要方便太多了,比如在MinGW中编译一个C++,注意,是C++,不是C,的程序,需要仔细地设置引用路径,而bjam中完全不需要,只需要一行代码就能搞定:exe Hello : Hello.cpp ;这个特性对我的情况来说也是很有帮助的,比如使用MFC的项目,鬼知道它要引入多少头文件路径,还有就是有个工程设计成既可以用VC编译又可以用MinGW编译,所以这又省了不少事。  再扯一个跟bjam关系不是很大的东西,编译使用了wxWidgets的项目。有一个小工具程序,可以方便地得到指定路径中的wxWidgets在编译时使用的选项,那就是wx-config。通过这个小东西,在编写编译脚本时,又可以省掉不少事。在http://wxconfig.googlepages.com/上可以找到Windows的移植版本,不过在bjam中使用时,会有一点点小问题,就是它的输出内容都在最后添加了一个回车,而bjam并不能让用户方便地设定编译选项在命令行上的先后顺序,所以如果恰好它的输出结果被排在命令行的中间位置,那之后的那些选项就被断开了,shell则认为这是两条命令,所以会出错。好在这个Windows移植版本提供了源代码,下载下来,自己稍微修改一下,也就是在输出的那条语句中把最后的std::endl去掉就可以了。  VC在支持预编译头文件时,一般是指定stdafx.h文件,然后加个编译编译选项来实现。在bjam中不能这样直接加编译选项来达到这个目的,而是专门提供了一个叫cpp-pch的规则来实现。不过,对于只在CI上才执行的bjam命令,有没有这个功能都无关痛痒。  VC有个很好用的特性,auto-link,boost就使用这个特性,这也使得在VC上使用boost比在其他编译器套件中要方便,它默认链接的都是静态库,使得发布都省了一些事。在bjam中使用时,只要设定好boost库文件的路径,其他的就不用管了。  在使用了MFC的项目中,会有一些特定的选项,比如它需要再指定程序的入口,这些工作本来都是IDE默默地在后台完成了,使用bjam时就需要自己留心了,一般的做法就是直接看项目属性中的命令行一栏,把一些个性化的设置都提取出来写到bjam编译脚本中去。

两个boost相关网站

  如果胆子足够在,这两个网站上的都是值得试一下的,其中不乏一些好东西,比如日志库就有两个,一个叫Boost.Logging,一个叫Boost.Log。  https://svn.boost.org/trac/boost/wiki/LibrariesUnderConstruction  http://www.boostpro.com/vault/  对于进入boost的侯选库,有两个存放点,一个就是上面第2个地址vault,还有一个是boost svn中的sandbox目录。从Review Schedule中看来,似乎进入Review的库从vault中来得多一点,而sandbox又有点像boost正式库的一个draft。

崩溃问题分析

  这两天在抽空分析程序的崩溃记录,这些记录都按照版本号分别放在不同的文件夹中。早先exe文件的版本号并没有严格对应于svn revision号,周一时用一个修改PE资源的小程序搞定了这个事情,以后做这方面的事可要精确和省神多了。  今天分析到一个记录,印象中以前也有过类似的记录,一时没想起来,发现是一个线程函数数,对一个std::map调用find方法,结果在STL内部引起崩溃了。开始的时候,还以为是调用find方法时传入的参数有问题,引发了STL的某个未定义行为。于是另外写了个小程序简单验证了一下自己的猜想,结果不如自己所料。后来猜测要引用这个map的对象时,包含它的指针已经无效了。但为什么无效,我却也得不出什么结论。最后突然想到,从崩溃记录分析得到的最后堆栈信息中,看到是调用find方法后,find方法中取xtree的根节点引起的崩溃,那么是不是这个map对象本身就是有问题的了呢?灵光一闪,这个map对象是做为一个类的成员的,如果这个类的实例被销毁了,这个map对象自然也跟着被销毁,而这时如果再试图访问它,当然会有问题。  分析出来具体的原因,修改起来就比较容易了,在该类的实例被销毁时,应该通知那个线程马上结束,而且不要再试图去访问那些它的成员了。在修改这块代码的过程中,我应用了boost::thread,这大大简化和缩减了需要编写的代码。

最近Boost有点疯啊

  什么Boost.DirectX啊,Boost.Debug啊,Boost.Cppgui啊,越来越疯狂了哦!

我晕std::locale

  今天一个同事突然发邮件来说我的升级程序在生成文件列表时,给数字都以3个数字一段都加上了逗号,我狂晕!拿自己的debug代码试了试,发现果然如同事所言,看来是确定代码写得有问题了!  单步跟踪,最后发现我在把数字转换成字符串时,用了std::stringstream类的流输入方法,就变成那种样子了,稍微想了一下就明白过来了,以前一直都是没有逗号的,后来有过修改的地方也就是当时用ofstream写文件时,为了能支持中文的路径和文件名,在程序启动时调用了一句std::locale::global(std::locale(""));后来就有了这个问题。我狂分特啊,跟另外一个同事分享这个经验时,他还问我为什么不用boost::lexical_cast呢,其实据说boost::lexical_cast内部也是用的std::stringstream来转换的,哈哈!

总有一些自以为是的傻x

  说什么无法控制,说什么循环引用,说什么编译时间,都他妈的傻x。怎么不去关心一下CPU能不能控制,Windows能不能控制,还不是他妈的那儿老老实实用着。怎么不去用一下汇编,Fortran,狗日的哪来的循环引用。怎么不去用Debug自己输入二进制码,哪来的编译时间。  莫装B,装B被雷劈!