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

Ubuntu10.4搭建支持Python与Php的web服务器

keyword: apache2+php5+python

想用Python开发点什么,但是部署真的是一个大问题,所以说Google Appengine的建立是有历史意义的,节省了多少时间啊。

不废话,直接上步骤。

Ubuntu用10.4,估计稍微低一点没问题,debian也应该没问题,apt-get安装好了build-essential、Python和Apache2+Php5(这个组合基本上不需要配置,直接apt-get就能搞定了)。

参考的文档是web.py的cookbook,http://webpy.org/cookbook/mod_wsgi-apache

之所以选择wsgi是因为mod-python好像许久不更新了,很难判断它是否还会继续下去,wsgi的性能据说不错,用于小站点上应该足够了。

wsgi可以从这里下载http://code.google.com/p/modwsgi 但是对于Ubuntu可以直接从软件安装程序(实际上就是apt-get的图形界面)直接搜索到wsgi。我就用的这种方式。

接下来很重要的一步,必须配置apache2,在/etc/apache2/sites-available里面default加入以下部分(可以在前面那个web.py网址上找到):

image

里面的重点是/appname和/webpy-app这两个目录,以及code.py这个文件。

/appname将会是你程序的子目录,也就是程序访问使用http://localhost/appname这种形式,而/webpy-app是web.py实际目录,code.py是代码文件的名字,可以根据你的需要进行修改。需要注意的是,/webpy-app最好不要放在www目录下,否则就会把文件列出来:

image

修改default需要root权限,sudo一下就行。改完default文件后,/etc/init.d/apache2 restart

仿照web.py cookbook的介绍写一个code.py,里面是hello world。

image

正常情况下,访问http://localhost/appname/就可以看到正确输出了,如果还有问题,就必须看apache的access log来判断具体什么地方出错了。

这种方法的好处是同时支持php和python,配置步骤也比较简单。等有空我再研究研究nginx+mod-wsgi的方式是否可行。