C语言表达式计算顺序的一个小问题

浏览Q.yuhen的博客这篇文章 http://www.rainsts.com/article.asp?id=959 发现一个小问题,估计有类似想法的同学也有,所以记录一下。

问题在于这句话:

“很显然,依据 cdecl 规则,"printf(…, test(2), test(1))" 中的 printf 函数参数依次从右向左 "入栈"(暂且用这个说法)。因此 test(1) 被先调用,然后才是 test(2),上面的汇编代码也说明了这点。”

尽管事实是这样的,但这是一个有问题的说法。

cdecl的入栈顺序是没错的,这个入栈顺序是针对每个逗号分隔的表达式结果而言。也就是说对于每个结果一定是这样的顺序。但是表达式计算顺序(或者说每个逗号分割的函数调用)其实是没有规定的。这在K&R影印版第二版52页最末一段说的非常清楚,下面的f和g不一定谁先调用:

C, like most languages, does not specify the order in which the operands of an operator are evaluated. (exceptions are && || ?: and ",") for example x = f() + g();

另外在63页开始:

The commas that separate function arguments, variables in declarations, etc., are NOT comma operators, and do NOT guarantee left to right evaluation.

这也就是说逗号分隔的函数参数与逗号操作符是不一样的,不保证从左至右的计算顺序(当然也没有保证从右至左)。

注意这个evaluation,其实就是对test(2), test(1)的调用。如果这些调用有边界效应,在不同编译器、操作系统上可能会得到不同的结果。另外类似的问题有对在参数列表中,同一个变量调用++两次以上。

如果要保证求值顺序(注意不是求值结果的入栈顺序),只能用临时变量保存调用结果,或使用逗号操作,&& || :?这样可以保证求值顺序的操作才行。

其实我在前面这篇博客已经提到了这个问题,只是看到这个提法再重申一次。“C语言中的表达式求值问题http://sunxiunan.com/?p=1684

参考资料:

http://www.andromeda.com/people/ddyer/topten.html 参考第七条

C陷阱与缺陷 3.7求值顺序

能打印出自己的代码

任务:写一段C语言程序,打印出自己整个代码,不能差一分一毫。

这个任务在计算机编程中有个术语叫做:Quine,维基百科上有专门的条目介绍。

http://en.wikipedia.org/wiki/Quine_%28computing%29

quine代码好像没有太大作用,但是我们可以将其想象成一种可以自我繁殖的生物,每次运行就产生一个同样的实体,然后一个个这样繁殖下去,哇塞,这就是恐怖片了!

搜索了一下,基于C语言(使用VC2010编译必须设置language为C才可以)主要有以下几种比较简洁的实现:

main(a){a="main(a){a=%c%s%c;printf(a,34,a,34);}";printf(a,34,a,34);}

这算是第一种模式,关键在于%c%s%c这个打印格式,然后输入参数中多半有34或者0x22(也就是双引号)或者引用到字符串数组中双引号的位置。

另外一种是通过宏定义实现的:

#define T(a) main(){printf(a,#a);}
T("#define T(a) main(){printf(a,#a);}\nT(%s)")

宏定义的实现消除了对双引号的使用,格式更为灵活一些,不需要是abab这种模式了。

关于quine一个非常详细的论文,介绍了深层理论、如何写quine代码等等,可以看看。

http://www.madore.org/~david/computers/quine.html

另外可以参考:

http://www.c4swimmers.esmartguy.com/selfcodeprint.htm

http://www.c2.com/cgi/wiki?QuineProgram

“大连自由软件日”活动简记

在元毅同学(@yuanyi_wang)的大力推动与强悍的执行力(数值至少有3万!)运行之下,大连第一次“自由软件日”活动于9月18日6点在大工研究生教育楼大教室胜利召开。

又是下点小雨,我从市内往大工方向坐车非常麻烦,要倒一遍车才能到。结果到的时候已经是快六点四十了,错过了Saka的关于Debian的讲演(Saka是大工老湿、BBS管理员、Debian team成员)。整个大教室里大概有六七十人,几位twitter上的朋友都在,大部分还是大工的学生。

关于ROR的讲演,非常浅显,基本上没有涉及到任何深一点的内容,比如Rails3.0也没有介绍,但是看底下同学反映好像也不怎么强烈,应该是了解的不多吧。

关于liferay的讲演,我也不是很感兴趣,因为java做框架开发已经不是web开发的主流了,现在php更为火爆一些,而且做portal方面的软件选择其实非常多,比如drupal、joomla、wordpress都可以,或者是python的zope,ruby的rails,开发效率应该都超过java。当然对于大连这嘎达,搞java的很多,用liferay也是很不错的选择。

Mark关于Linux的内核讲演非常有意思,我算是听懂了百分之八十吧,因为自己对BSD、Solaris、Linux也有一些兴趣。他语速不是很快,并不是很难懂。Mark比较了各个版本Unix的内核实现框架,以及虚拟化这个很潮的概念,是非常棒的一个ppt,只是我不做Linux开发,很难体验精华所在,有些可惜。最后我问了一个关于“BSD和Linux成功学”的问题,为何Linux现在更帅更成功?Mark的答案是Linux更适合现在Internet的开发,即使代码质量不如BSD,但是庞大的社区让Linux更快实现一些开发者需要的功能。

活动结束后我们几个twitter上的朋友和讲演者合了影(等我要到了跟大家share)。总体来说活动还是非常成功的,打开了大连这地方只有外包没有技术氛围的尴尬局面。下一周还有一个活动关于Ruby,希望类似的活动越来越多,让大连的开发者能组织起来,有更多的交流沟通,更好促进开发者的发展。

使用Python自动化Windows界面操作

要拷贝几百个文件到另一个目录,有重名现象,但是不想覆盖原有文件,在命令行下应该可以通过命令行开关来完成需求。

但是已经开始拷贝,而且就想使用界面操作,怎么办?(太纠结了!)

好在我们有Python可以使用。

http://www.tizmoi.net/watsup/intro.html

http://www.brunningonline.net/simon/blog/archives/winGuiAuto.py.html

其主要设计思想就是使用Windows API找到特定窗口,然后发送键盘或者鼠标消息。

watsup我使用Python2.6,然后安装了PyWin32,还有SendKeys库,最后下载watsup,解压到Python的lib目录即可。

代码极为简单,我对winGuiAuto稍作修改,加了equalText参数,因为原来的wantedText使用的是(wantedText in targetWindows),只要有"No"在字符串里面就会返回,与我想达到的效果不太一样,当然也可以用selectionFunction加lambda完成,但不想费那劲了。

 1: from watsup.winGuiAuto import findControl, findTopWindow, clickButton

 2: from time import sleep

 3:  

 4: aWindow = findTopWindow(wantedText='Confirm File Replace')

 5: while aWindow:

 6: button = findControl(aWindow, equalText='No')

 7: sleep(0.1)

 8: clickButton(button)

 9: sleep(1)

 10: aWindow = findTopWindow(wantedText='Confirm File Replace')

如果你使用Ruby,可以参考这篇,也是一样的使用相关Windows API。

http://rubyonwindows.blogspot.com/2007/05/automating-applications-with-ruby.html

美能达x700第一卷

一方面是喜欢胶片的粗糙感觉以及拍摄以后等待冲洗的那种心情,另一方面,也是主要原因暂时没那么多经费上数码单反,于是从ebay上拍了一台胶片单反相机。

这台胶片单反相机已经有将近30年的历史,曾经在八十年代初得到欧洲相机大奖,也号称是用了它就能达到美。没错,就是美能达x700。

第一卷使用Kodak proimage100胶卷。

下面的片子都没有经过ps处理(当然不排除店家扫描的时候p了),第一卷完全使用P模式。

32230004

这是高尔基路。

32230010 

刚起床,这是开头几张,很没经验,对焦对到衣服上了。

32230012

32230013

妈妈养的花。

32230015 

过曝了,不过还算能看。

32230022

萌萌在疯跑中。

32230028

32230030

装成熟的小女孩。

32230035   

拿着巧虎星象仪。

32230036

爷孙俩。