2009-07-20

牙疼

牙疼了两个礼拜,中间好几个夜里痛醒,有几晚基本只能靠门牙切割食物而毫无咀嚼功能,苦不堪言。实在扛不过去,于是请了半天假去医院 -- 兄弟们根据经验说我这个案例不用拔牙,补牙就行,介绍了一堆经验。

下一点半离开公司,太阳毒辣得让人怀疑是否生活在火星,感觉自己的全身被炙烤。医院大楼的门口相当阴凉,几乎让人打起冷站。挂号后去口腔科取号排队,等了二三十分钟后终于轮到我。

目睹了一件件器械,回想起来有点毛骨悚然。我那颗牙的蛀牙史已经相当长,已经严重得可以轻松放入一整粒米。闻着牙齿被磨的焦味,胃开始痉挛。加上不知名的药水,还有一种能直接磨到牙洞内部的器械,我不住的向身边的器皿吐掉口中的渣滓。那种药水、渣滓混合的味道,刻骨铭心。出医院后,舌头不自觉的吸了一下那边的牙缝,差点吐在路边。

LP说我的鼻炎是硬撑出来的,这次的牙疼也是。我想也是。对于鼻炎,我是没想到重感冒会有如此后遗症;而对于这颗牙,大概是我片面相信了商业软件的准则:if it works, don't touch.

无论如何,健康最重要,预防乃是健康中之最最重要!望朋友们以我为戒!切之勿忘。

标签:

生活在贵国

在贵国生活真的是件劳心劳力的事情,而且看不到尽头。通货膨胀,楼价上涨,汽车肇事,建筑倒塌 -- 一件件都让人堵心。 此处省略万字。

标签:

Ubuntu - The Killing App of Linux Platform

第一次正式接触的Linux发行版是RedHat 7.1,2002年。后来用的比较长时间的是RedHat 7.3,因为只有在那个版本我才能使我台式机的内猫正常工作。后来用奖学金买了RedHat 7.3/8.0,价格都是RMB 68,但基本上都是给同学安装了。实习后买了本本,开始装的SuSE,而放在老家的台式机上跑的是Debian 3.0。后来转向ubuntu,从5.10至今,一直apt-get dist-upgrade到Jaunty 9.04,基本没有出现任何问题。

当年TA问我为什么用ubuntu,是不是因为它polished,我说不是,只是用着比较方便、顺手 -- 我不想回到手工配置一切,到处找驱动的时代。实际上,过去的一年多我的本本里面就跑了个wmii,怎么看怎么原始,但是方便、快捷,还自我感觉有点酷。

前几天开机发现fsck,不放心,于是重新格式化硬盘,重装了系统。试了ArchLinux, Debian,最后还是用了ubuntu。装完之后才发现原来如今的ubuntu看上去已经如此养眼。有句话是这么说的:You can't sell a platform without a killing app on it.  Linux内核无论做的多么牛B,如果没有杀手级应用,那么也仅仅寥胜于无吧。用ubuntu作桌面系统无疑是让人快乐的,我又从wmii回到Gnome桌面。

标签:

2009-07-18

Display Chinese TXT File in Vim/Emacs

For Vim, put the following line in ~/.vimrc:
set fileencodings=utf-8,cp936


For Emacs, add the following to ~/.emacs:
(custom-set-variables
'(current-language-environment "Chinese-GB"))

标签: ,

2009-07-15

Even when one byte matters

前几天读了一篇文章,``Even When One Byte Matters''。然而今天我就犯了个指针越界的错误,虽然也仅仅是越界了一个字节,其效果就像上帝显灵一样,令人印象深刻。

是一段算字符串md5值的程序,主函数中的变量声明如下:
int i;
char asc_buf[MD5_DIGEST_LENGTH * 2];


``asc_buf'' 中存放的是字符串md5的值转成ascii的形式。MD5摘要的长度是16,而字符串形式的长度是它的两倍,也就是32。然而,一个粗心,这个数组少定义了一个字节 -- C的字符串以一个额外的'\ 0'结尾。然后,在另外一个md5_to_ascii( )函数中,有这样一句:
asc_buf[MD5_DIGEST_LENGTH * 2] = '\ 0';


于是,它的结果是把i的值设为了0 (精确一点的说,是i的最低或者最高字节为0,取决于大端还是小端)-- 想想堆栈的布局便很明白了。如果这段程序没有测试,便提交到了一个很大的项目里,这个bug还是比较隐蔽的。C的强大得益于指针,而指针也恰恰是万恶之源。双刃剑。

标签:

2009-07-14

墙里秋千墙外道

念叨着远在西非的大狼这两天怎么没来电话,效果竟然非常灵验,前天晚上真的通了电话。死狗问我婚后感觉怎么样,有么有什么变化。我说没有,就像精神上入党和组织上入党那样没啥区别。

要是仔细求证之间的区别,那还是有的吧。我无法每天一篇博文,而且似乎已经不能像以前那样对某件事情专心致志。婚姻对我来说是交出一半的思想,谨慎用语,不再年少轻狂。生活在同一屋檐下,磕碰自是在所难免。很多事都介于"不说憋屈"和"说了矫情"之间。

听说钱钟书先生对杨绛女士有这样一段评价,后来被社会学家视为理想婚姻的典范:

  1. 在遇到她以前,我从未想过结婚的事。

  2. 和她在一起这么多年,从未后悔过娶她做妻子。

  3. 也从未想过娶别的女人。

标签:

2009-07-09

Guile Scheme Macro Bug?

syntax-rules是R5RS Scheme中规定的标准hygienic macro system,不过Guile Scheme中的实现似乎有点问题。
(define-syntax dotimes
(syntax-rules ()
((_ n body ...)
(let loop ((counter n))
(if (> counter 0)
(begin
body ...
(loop (- counter 1))))))))

上面定义了一个宏dotimes。理论上说,作为hyginic macro,外部环境对于宏里面的内部符号应该没有任何影响:

> (let ((loop 2)) (dotimes 4 (display loop)))
2222
> (let ((n 2)) (dotimes 4 (display n)))
2222
> (let ((counter 2)) (dotimes 4 (display counter)))
2222
> (let ((- 'minus)) (dotimes 4 (display -)))
minusminusminusminus

MIT-scheme, Gambit以及PLT中都是上面的行为,唯独Guile过不了最后一关:

guile> (let ((- 'minus)) (dotimes 4 (display -)))
minus<unnamed port>: In expression (- syntmp-counter-21 1):
<unnamed port>: Wrong type to apply: minus

明显的是,宏内部变量名都已被转换,比如counter变成了syntmp-counter-21,但'-'还是引用了外部let环境下的'-'。这该是个bug。

标签:

Dr. Dobb's Survey DVD

前天夜里看到Dr. Dobb's有个survey,前100个参加者可以得到DVD。上午打开电邮才知道我居然也是前一百之一!回复了Postal Address,坐等。

标签:

2009-07-05

逆波兰表达式计算器

今天在learnyouahaskell.com上看见一段逆波兰表达式计算器的代码,挺美妙的。
solveRPN :: (Num a, Read a) => String -> a
solveRPN = head . foldl foldingFunction [] . words
where foldingFunction (x:y:ys) "*" = (x * y):ys
foldingFunction (x:y:ys) "+" = (x + y):ys
foldingFunction (x:y:ys) "-" = (y - x):ys
foldingFunction xs numberString = read numberString:xs

第一行是函数solveRPN的类型声明,略过。简单的流程解释一下就是:先用words将字符串tokenize,然后用上foldl扫描归纳之,最后将结果存在list的第一个节点,用head取出来。简单明了,一气呵成。比如,给定字符串"10 8 + 2 -"。下面是归纳步骤。

words "10 8 + 2 -" 得到 ["10", "8", "+", "2", "-"],接下来便是:foldl [] ["10", "8", "+", "2", "-"]。应用传递给foldl的函数foldingFunction,得到运算过程:

  1. fold1 [] "10" [""8", "+", "2", "-"]

  2. foldl [10] [""8", "+", "2", "-"]

  3. foldl [10, 8] ["+", "2", "-"]

  4. foldl [18] ["2", "-"]

  5. foldl [18, 2] ["-"]

  6. foldl [20]


foldl结束后head [20],便得到20。需要注意的是第六行,它的意思是(read numberString) : xs,而不是read (numberString:xs)。优先级问题哈。

标签:

自来水表也有故事

周四下班回家,看见门缝中留了张字条。来自自来水公司,大意是在周一至周五,下午2:30~3:30之间打某个电话与之联系。第二天打过去以后,才知道门外那个水表非自来水公司生产(对方称之为“假表”)。心里一个咯噔,“坏了,要是赖我偷水那可如何是好?”不过回过神来想起有租房合同、缴费存根等可据。谅无大碍。

周日,约了自来水公司的人(A)和房东(B)一起过来。扯了十几分钟,最终才发现这不是数据问题(用水量可以解释清楚),也不是现在的水表的精度有多少问题,而是价格问题。
A: 我可以排除这不是你们私换的表,这就很简单了,你就买个水表换上问题就解决了嘛。

B: 那我现在这个表有什么问题?

A: 公司规定 -- 你可以认为这是霸王条款,必须用我们自来水公司生产的水表。市场上的表嘛也就二十块钱 -- 我们的水表卖125.1

B: 既然只允许用你们的水表,那市场上卖别的表也没用啊!

A: 你可以装在屋子里面,当做分表嘛!

P.S. 现在水表都装在屋外,锁在铁盒之中,只有自来水公司工作人员可以打开。业主只能打开一个小门,开关阀门而已。想接触到水表基本上不可能(除非把那铁盒给打开)。

标签:

2009-07-03

valgrind against glib

上午同事说valgrind在扫描基于glib的程序时有些明显的内存泄漏没有报过出来。有点不相信,因为之前每次怀疑valgrind的时候最终总是证明是自己的代码写的不对。于是,将信将疑之下用valgrind扫了一下下面的程序:
GList* list = NULL;
GList* i = NULL;

list = g_list_append(list, g_strdup("first"));
list = g_list_append(list, g_strdup("second"));

for(i = list; i != NULL; i = g_list_next(i)){
printf("%s\n", (char *)i->data);
}

令人难以置信的是,其结果居然是:
==6509== LEAK SUMMARY:
==6509== definitely lost: 0 bytes in 0 blocks.
==6509== possibly lost: 0 bytes in 0 blocks.
==6509== still reachable: 4,569 bytes in 10 blocks.
==6509== suppressed: 0 bytes in 0 blocks.


两次g_strdup()出来的内存显然没有释放,而且链表本身占有的内存也没有释放,但valgrind的definitely/possibly lost居然都是0!如果把上面的printf()函数换成glib里面的g_print()函数,结果又有所变化:
==6519== LEAK SUMMARY:
==6519== definitely lost: 0 bytes in 0 blocks.
==6519== possibly lost: 744 bytes in 3 blocks.
==6519== still reachable: 5,407 bytes in 18 blocks.
==6519== suppressed: 0 bytes in 0 blocks.


这次不但多了744字节的possibly lost,还多出了838字节的still reachable。Google了一把,发现这个问题似乎和glib的slice allocator有关系。参考这里。如果想让valgrind展现出正确的行为,请将环境变量G_SLICE设为always-malloc。


# G_SLICE=always-malloc valgrind --leak-check=yes ./foo
...
==6522== LEAK SUMMARY:
==6522== definitely lost: 12 bytes in 1 blocks.
==6522== indirectly lost: 25 bytes in 3 blocks.
==6522== possibly lost: 0 bytes in 0 blocks.
==6522== still reachable: 1,638 bytes in 9 blocks.
==6522== suppressed: 0 bytes in 0 blocks.

标签: ,

2009-07-02

Sierpinski Triangle

下面的图形被称为"Sierpinski Triangle":
sierpinski triangle

生成它的代码很简单,比如用guile (需要guile-cairo):

(use-modules (cairo))

(define (polygon cr p1 p2 p3)
(let ((x1 (car p1))
(y1 (cdr p1))
(x2 (car p2))
(y2 (cdr p2))
(x3 (car p3))
(y3 (cdr p3)))
(cairo-move-to cr x1 y1)
(cairo-line-to cr x2 y2)
(cairo-line-to cr x3 y3)
(cairo-line-to cr x1 y1)))

(define (fill-tri cr x y size)
(polygon cr (cons x y)
(cons (+ x size) y)
(cons x (- y size))))

(define min-size 8.0)

(define (sierpinski-tri cr x y size)
(if (<= size min-size)
(fill-tri cr x y size)
(let ((new-size (/ size 2)))
(sierpinski-tri cr x y new-size)
(sierpinski-tri cr x (- y new-size) new-size)
(sierpinski-tri cr (+ x new-size) y new-size))))

(define surf (cairo-svg-surface-create 300 300 "foo.svg"))
(define ctx (cairo-create surf))

(cairo-set-source-rgba ctx 1 0.2 0.2 0.6)
(cairo-set-line-width ctx 2.0)

(sierpinski-tri ctx 25 275 255)

(cairo-stroke ctx)
(cairo-surface-finish surf)


如上,结果会保存在文件foo.svg中。

标签:

X11 forwarding in Arch

ArchLinux里sshd的X11 forwarding默认似乎没有打开。嗯,那就修改一下/etc/ssh/sshd_config吧。
X11Forwarding yes
X11DisplayOffset 10
X11UseLocalhost yes

标签: