巴别塔上的雇工


看球
6月 26, 2006, 12:57 上午
Filed under: 八卦杂谈
上个周末终于进入淘汰赛了,一开始寻思着这下子各路人马应该卖力地踢了吧,所以还熬夜看了几场,不过11点直播的似乎都是弱队力不从心,没什么精彩的。刚开场的时候还有点劲头,看到下半场12点多的时候,又困又乏,想着外国佬踢球关我什么事,明天直接看比赛结果吧,睡觉zzzz
 


我再预测一下
6月 23, 2006, 1:12 下午
Filed under: 八卦杂谈
前几天预测韩国输,没想到他们赢了,再预测一下:今晚法国大胜多哥,韩国负于瑞士,亚洲球队里面只有一个半路出家的澳大利亚小组出线,输就干脆输个底朝天吧!
 
经常听某某球队战略考虑,不想小组出线之后碰上什么什么队,我觉得这种想法真是没有志气,你要真爷们,应该迫不及待的和强者较量一下,大不了就是输嘛,金杯就是一个,拿个第四合拿个第八我觉得没有什么区别,这些国家的足球领导可能也有政绩思想,想着在我手上这届能过多进一步就ok了,和我国的某某机构主任的想法没什么本质区别。
 


谈论问题
6月 23, 2006, 3:14 上午
Filed under: 工作心情

 

问题

 
给一个pizza,一把刀,如何三刀把它切成八个完全相同的小块?
不能折叠,也不能象立方体一样横着切一道。
 
不能折叠?
我先两刀分成4个相等的,然后把它们像下面那样连成一串
(>(>(>(>
横着一刀,成了8块一样的,没有折叠哦:)
 
另外一个有趣的题目是:
假设一个字符集只有8bit宽。现在已知一个函数char tolower(char c),能将c转变为小写。要求写一个函数,char toupper(char c2),将传入的字符转变为大写。
 
不知道这题要考察什么,不利用tolower直接写toupper似乎更加简单。
char toupper(char c2)
{
    if ( c2 >= ‘A’ && c2 <= ‘Z’ )
       return c2 – (‘A’-‘a’);
    else
       return c2;
}
 


背水一战之前先吹个大牛皮
6月 22, 2006, 9:41 上午
Filed under: 八卦杂谈
日本主帅济科豪言要战胜巴西 期待能多捞几个净胜球
“在上届 世界杯中,日本队打进了16强。本届世界杯济科的目标则是要超过上一届的成绩。他最常挂在嘴边的话就是:“在足球比赛里,任何事都可能发生。”而济科也把法国世界杯作为例子。1998年法国世界杯中,尽管还是小组出线,但巴西队在最后一场小组赛中输给了不被看好的挪威。也许日本队也可以复制同样的奇迹。”
 
我看除非巴西看在济科是老乡的情面上胡乱踢两脚,不然小鬼子是肯定过不了这一关了。
 
那天看日本对克罗地亚,终场之前几秒钟电视上给了一个日本女球迷一个特写,这个女球迷双手合十祈祷,接着裁判就吹哨了,这个女球迷马上欢呼起来。不明白,打平了你们就没戏了啊,shout what shout啊?
 
 


徐静蕾的Blog是世界上最火的Blog?
6月 21, 2006, 11:49 上午
Filed under: 八卦杂谈
Technorati虽然号称全球最牛的Blog搜索引擎,但是中文搜索我觉得很弱,他们的网站也没有中文版,不过在满篇的英文中间,却总是能看到这样几个中文
  •  老徐 徐静蕾 新浪BLOG
  •  Boing Boing
  •  Engadget

排名第二、三的BoBo和Engadget也够卖力的了,今天把他们加到bloglines里面,每隔几个小时都有新的feed,还是架不住徐静蕾小女子啊,应该说是架不住人多。中国人一人吐口吐沫,就可以淹没东京,一人链接一下老徐的Blog,就没有哪个外国佬的Blog人气能够匹敌。这市场真是庞大,难关外贸谈判没谈成,老外都要哭了。

 



VC event handling VS. QT signal-slot
6月 21, 2006, 4:40 上午
Filed under: 技术体会
这两天碰上几个微软技术上的概念,差点把我搞糊涂了。在Windows API中有一个Event的概念,有点counter-intuitive,其实是用来做Thread之间同步的,类似于pthread的wait condition;VC中又有一个event handling的概念,看起来和QT的signal-slot很相似。
 
VC的event handling通过__event,__hook,__raise,__unhook这些关键字来实现,例如
 
[event_receiver(native)] //这两个attribute我试验了一下,对native C++其实是
[event_source(native)]  //可有可无的
struct Foo
{
   void MyHandler(int nVal)
   {
       _tprintf(_T("MyHandler %d"), nVal);
   }
   __event void MyEvent(int nVal);
};
 
int main()
{
    Foo f;
    __hook(&Foo::MyEvent, &f, &Foo::MyHandler, &f); //建立连接
    __raise f.MyEvent(13); //激发event
    __unhook(&Foo::MyEvent, &f, &Foo::MyHandler, &f); //断开i连接
}
程序运行结果
MyHandler 13
 
一说event总是让人感觉是异步的东西,其实这里的event是同步的东西,__raise语句实际上就是把所有__hook过的handler都调用一遍,没有event loop存在,在Winodws里面,这样异步的东西叫做Message。
 
QT中间的signal-slot机制类似,和VC的编译器直接支持不同,QT要求用它的pre-compiler处理以下再用compiler去编译,这样实际上把编译过程复杂化了一点。但是至少有一点QT还是VC强,那就是在QT中,handler所在的对象如果析构了的话,连接就自动中断了,但是VC不这样,所以如果handler的的对象已经西沟,而没有__unhook的话,再次__raise event的时候还是回去调用这个handler,这样会产生不可预见的错误,有可能就是一个access violation。
 
 


屠虫战记
6月 20, 2006, 1:29 下午
Filed under: 技术体会
“唯一的好bug是死bug”              ——《星河舰队》                 

加入MS之前看过一个MS前辈写的《C++ In Action》,中间他说程序员大部分时间都是在修改别人的code,fix前人留下来的bug,托他吉言,现在我相信他的话了。
 
Fix一个bug需要十八般刑具,首先Debugger需要有WinDbg或者VS2005,code编辑器我还是喜欢用vim,看Code似乎没有比SourceInsight更好的工具了,最后还要用上google/msn search……
 
以这几天要处理的一个bug为例,一个COM component不知道为什么在Console Application运行的好好的,在我们的Active里面就是不工作。老办法,先用Debugger来track以下到底是哪里出了问题,结果发现CoCreateInstance直接就返回E_NOINTERFACE了,但是天地良心它的确支持这个Interface啊。
 
伙计,我知道干我们这行不应该迷信,但是这些灵异现象也够让人害怕的。碰上这种情况往往就要看看前人经验,所以直接用Search,先用google,输入CoCreateInstance+E_NOINTERFACE然后按下回车的时候心里想,小样,现在虽然打不败你,但是还不能利用以下你么,嘿嘿~~不过搜出来的结果全是教课书一样的说E_NOINTERFACE表示这个component不支持这个接口,算了,还是用MSN Search吧,因为工作性质的关系,MS技术相关的用MSN Search可能搜出来的更加准确,不过这次运气也不是很好,还是没有搜出相关的解释。
 
也不能所有的bug都要马上fix,需要检要紧的先来处理,这个bug虽然诡异,priority倒不是很高,所以先放下。
 
好了,别的bug都搞定了,现在回头来看看这个bug,Search帮不上什么忙,看样子只好强攻了。MS曾经花钱雇了世界顶级屠虫战士(bugslayer)John Robbins同志来给我们传授过屠虫之技,我们现在都称呼他为“讲Debug的那哥们”,Robbins似乎十分崇尚用Debugger通过Symbol Table的支持来读CallStack以此发现bug所在,MS对外公布了几乎所有产品的symbols,但这些symbols并没有让reverse engineer容易一点点。我设好Debugger的Symbol Server,然后试着Walk以下Stack,发现这玩艺比我想象的难多了,看汇编代码基本上不大可能看出是什么环节上导致CoCreateInstance失败。
 
不过并不是没有出路了,还可以从论坛上找,在newsgroup上找了一下,也没哟什么满意答案,发了一个post,不过估计没人能回答。网络进化到今天,有一样东西还是饱含个人经验的,那就是blog,试试technorati,结果搜出来的结果牛头不对马嘴,technorati搜索技术型文章真的是不行,搞不懂为什么名字里面还带tech,搜索结果没多少带技术的。要说技术性强,有个地方是首选,blogs.msdn.com,果然,光是搜索CoCreateInstance这个关键词第一页就有一个Why do I get E_NOINTERFACE when creating an object that supports that interface? 不愧是老鸟云集之地!
 
回头说这个bug,原来是因为这个COM component在注册表的InprocServer32中没有ThreadingModel这个值,这样这个component就自动属于main STA了,但是ActiveX在IE里运行,线程毫无疑问不属于main STA,所以需要Marshal,但是这个component的作者肯定没有做marshal,所以CoCreateInstance就返回一个E_NOINTERFACE。一开始怎么也没往Threading Modell上面想啊!
 


《Ice Age 2》不错
6月 19, 2006, 12:09 下午
Filed under: 八卦杂谈
因为我积极参加公司的survey,赚到东方新天地地下影院的两张电影票整个六月份似乎只有《Ice Age 2》还值得一看,上周六和LP去把这两张票消费掉了。
 
在门口等开场的时候,听到一个刚出来的家长教育她的孩子,说那只小松鼠为了拿到他的橡子,坚持不懈,最后因为他的坚持,把他的伙伴们救了,所以人有时候就是需要坚持。后来自己看了,知道其实那只松鼠还是不认识毛象/剑齿虎/树懒他们,谈不上伙伴,而且最后松鼠砸开冰坝放走洪水也是无意为之,主观上还没料到冰坝裂开了,不过那位家长真是能够做即时的家庭教育,佩服佩服!
 


老大不干了
6月 16, 2006, 12:17 下午
Filed under: 工作心情
今天MS公布了这个消息,BillG在2008年会退居二线……应该是三线,六年前已经算是退居二线了。
 
我联想到了,当年,毛主席领导中国人民打下江山取得新民主主义革命胜利,之后在国内经济建设方面一再受挫,要是早点放手让刘少奇去干,现在会是怎样,毛主席看到了问题,但是又不愿意放权给别人去解决,继续犯政策错误,如果能够放手让年轻的邓小平去干,又会是怎样?毛主席的晚年是他光辉一生的一个遗憾,后人不应该犯他一样的错误。话说回来,BillG哪有毛主席伟大啊:)
 
 


SEH的EXCEPTION_CONTINUE_EXECUTION
6月 16, 2006, 8:54 上午
Filed under: 技术体会
因为工作需要,又要研究一下C++的Exception机制,用MSVC的话,自然又要了解一下Windows的Standard Exception Handling(简称SEH,不是SHE),实际上MSVC的Exception机制就是基于SEH的。
 
在这个链接(http://51cmm.csai.cn/ExpertEyes/No159.htm)上,介绍了一下SEH在VC中的体现,就是__try/__except关键字,在__excep后面的()中是一个表达式,值可以是
EXCEPTION_CONTINUE_EXECUTION (–1) 异常被忽略,控制流将在异常出现的点之后,继续恢复运行。
EXCEPTION_CONTINUE_SEARCH (0) 异常不被识别,也即当前的这个__except模块不是这个异常错误所对应的正确的异常处理模块。系统将继续到上一层的try-except域中继续查找一个恰当的__except模块。
EXCEPTION_EXECUTE_HANDLER (1) 异常已经被识别,也即当前的这个异常错误,系统已经找到了并能够确认,这个__except模块就是正确的异常处理模块。控制流将进入到__except模块中。
 
文中还举了一个使用EXCEPTION_CONTINUE_EXECUTION的例子,如下
#include <stdio.h>
void main()
{
   int j, zero;
   puts("hello");
   __try
   {
        puts("main()函数的try块中");
        zero = 0;
        j = 10;
        // 下面将导致一个异常
        j = 45 / zero;
        // 注意,异常出现后,程序控制流又恢复到了这里
        printf("这里会执行到吗?值有如何呢?j=%d n", j);
   }
   // 注意,这里把zero变量赋值为1,试图恢复错误,
   // 当控制流恢复到原来异常点时,避免了异常的再次发生
   __except(puts("in filter"), zero = 1, -1)
   {
       puts("main()函数的except块中");
   }
   puts("world");
}
上面的程序运行结果如下:
hello
main()函数的try块中
in filter
这里会执行到吗?值有如何呢?j=45
world
Press any key to continue
 
也许在原作者的开发环境下,的确是这个结果,但是……
 
这段程序想演示一个recover exception的技巧,在C/C++中,用逗号串起来的表达式还是一个表达式,这个整体表达式的值是最后一个表达式的值,所以puts("in filter"), zero = 1, -1的返回值是最后一个值(-1),也就是EXCEPTION_CONTINUE_EXECUTION,而之前的表达式也会被evaluate,也就是"in filter"会被打印,而且zero也会被赋为1,这样,在这个thread回去再次执行j = 45 / zero;的时候,zero已经是1了,于是是不会再次有异常发生。真的是这样吗?不见得,在我的机器上,这段程序陷入一个死循环。
 
我用VS2005的Debug模式看了一下生成的汇编代码,发现问题所在了,zero的值一开始就被MOV到ECX中了,然后把45这个常数MOV到EAX中,然后IDIV EAX, ECX,再看__except部分的汇编代码,zero=1的汇编代码只是修改了表示zero的内存,并没有动ECX,这样__except在ignore这个exception之后,并不是直观上的回去执行“j=45/zero”这个C++语句,而是去执行“IDIV EAX,ECX”这条机器指令,而这时候ECX还是0,所以又是一个exception,陷入死循环!
 
从中需要加深几点意识:
1) __except(EXCEPTION_CONTINUE_EXECUTION)是让thread回到发生exception的机器指令,不是回到发生exception的C/C++语句;
2) 没有多少适合用__except(EXCEPTION_CONTINUE_EXECUTION)的场合,除非__try部分是用汇编写的。