Archives

又看了几部电影

快过年了,实在是没心思弄别的东西了,就跟着随便玩玩吧!于是乎,又看了几部电影,简单点评一下。

《凤凰》: 这个是上次看的,忘了写了。应该是一部老电影了,讲述的是一个古老,经典的爱情故事~~

《这个男人来自地球》:公子同学鼎力推荐的,不能不看。确实不错,应该算是科幻电影,虽然没有一个科幻镜头。看了之后觉得,哎,读书人啊,都是认死理,一个观点如果驳不倒它就只能被迫接受。如果你知识足够丰富,丰富到没人能揭穿你,那你就可以去撒一个弥天大谎!片中的情节和某一期《科幻世界》中的一个故事很类似,不同的是后者讲的是一个人也是活了上千年,他会也变老,只是变得很慢很慢,然后当他在进行欺骗时遇到了一个正在使用同样手法的同样的女人……

《耳朵大有福》:范伟演的又一部好电影,相当不错的国产电影!推荐一把。电影讲述的故事太贴近现实了,简直就和真实生活一样。有人评论说是“喜剧的皮包着生活的馅”,太准确了!!

《罪恶之城》:又是一部以暴力为主的电影。老大说俺是不是有暴力倾向了,当然不是了,俺是听了好几个人给俺推荐之后才决定去看这部电影的。这确实是一部好电影!通过血腥和暴力讲述爱!三个故事虽然都是处处暴力,但却又都是围绕着“爱”这个主题讲述,尤其是最后一个故事,很感人!整个电影的格调和《辛德勒名单》一样以黑白为主,仅有一些女人的衣服和一些流血为红色,还有一个恶人是恶心的黄色!对比太显著了!通过这种方式展示的爱有一种极其悲壮的意味……

解答 C Puzzles

今天看到某人列出了几十个C语言迷题,很有意思。顺手做了一下,发现其实大多数都是来自C Faq,Expert C Programming,和网上出现的一些C语言技巧,一些很好,连我自己都被难住了,一些却又狠简单狠基础。除了第8个和第26个需要进一步理解,剩下的我全都作了简单的解答,不明白的请留言提问。

题目在这里:http://www.gowrikumar.com/c/

我的解答如下:

1. 见ECP第29页,一模一样的例子。

2. OS_HP-UX_print这不是一个有效的名字。//blush 一开始我也没注意到!

3. do-while的常识,你应该知道continue到哪里。如果不知道,看看C99第6.8.6.2节。

4. 常见问题,因为stdout是带缓冲的,如果不换行的话,是会有问题的!

5. h会被展开,而g不会。见C-FAQ,Question 11.17。

6. case后面的是字符,不是整数。

7. IA-64是RISC,不能访问未对齐的地址。

8. 感觉没错,但还未发掘出其原理。。。

9. 直接比较浮点数被认为是有害的,说过多次了。

10. 常识。如果很喜欢在初始化时用逗号运算符来标新立异,请加括号!

11. 当然合法!谁还以为printf是void类型?!它返回的是成功输出字符的个数!

12. duff’s device,是用Tom Duff的名字来命名的。很有名的一个东西,用来优化拷贝的,据说和Rob Pike此牛还有点儿关系~!不过注意,原始的duff’s device中的to可是不变的,因为它指向一个映射到内存的寄存器。

13. 正确,逻辑很简单,每次都保留除最低位置的1之外的1,减去1,依次测试。

14. 说过N^2次了,int foo()和int foo(void)是不一样滴!

15. 第二个是把a的内存比特位模式用int来解释。
第一个比较有意思,因为类型不匹配,而且float在被压入压出的过程中会被扩展精度,因为IA-32的浮点数寄存器都是80bits的。所以,float会被扩展成double后再当int处理!!

16. 声明的问题,指针不是数组。

17. switch嘛,当然会跳过第一个case/default之前的东西,所以初始化就被跳过了。

18. 切,形参写得再好数组也得退化啊!

19. format string overflow?!

20. C99 第7.19.6.2节,第5条。

21. buffer overflow

22. sizeof是操作符,编译时决定的,而非运行时。

23. ECP,第25页。

24. 等号优先级高于逗号。

25. 减法和除法错误,减数和被减数反了,除法同理。

26. 蛮牛的一段代码,还没看出其中的奥妙。以后看懂会另行说明。;-)

27. 以0开头是8进制,而最后一个是十进制。

28. scanf返回成功输入的个数。

29. /和*会被当成注释处理,所以那一行实际上是y=y;

30. -也要被输入。

31. &n

32. 加号优先级高于左移。

33. 当然不合法,return不能出现在表达式中。

34. 把for括号里的最后一个i换成n。暂时就想到这一个解法。

35. 显然ptr2不是指针。

36. 错误!因为会被0除!

37. 很明显是8。

38. free的地址不对。

39. 很简单,就是把a[n]换成了n[a],本质上一样。

40. 字符a前面的所有,见C99 7.19.6.2.12。

41. 一个是定义,其余是声明。

42. 取某个成员在其结构体中的偏移。

43. 就是宏的常见错误,比如:SWAP(a++, ++b)。

44. 某个表达式及其对应的值。

45. 参见Python源代码,Objects/intobject.c::int_add。

46. n/x向上圆整!

47. c会被自加两次。

48. 不能一个参数都没有就使用“…”。

49. 用?:三元操作符。;-)

50. 把输出字符的个数存入某个变量中,见过。

51. -_-b

52. %%

53. 后一个指针只读,前一个指针指的东西只读。

54. 前者不能重叠,后者可以。

55. %lf, %f, %g。就记起来这仨。

56. 写过N遍了。。。

57. 厄,看我这个:

include <stdio.h>

int main(void)
{while(printf(“Hello World!”)<0){}}

很美的一段词

人间离魂多

添憔悴

谁记冷香

终只剩两茫茫

释然隔江

既是云鬓染霜

莫为落花断肠

————孤单的分割线————

不知道这段词的作者,在网上搜居然也搜不到任何有用的信息~ !

知道的人请吱一声。

sudo和tee

今天刘洋同学问到一个问题,为什么sudo下面的命令还是无权限

$sudo echo ‘1’ > ip_forward
bash: ip_forward: Permission denied

而以root身份就可以?

# echo ‘1’ > ip_forward

一开始没有看出原因来,后来仔细一琢磨,其实原因很简单,shell对‘>’解释干扰了对这个命令含义的判断。我们本想应该是这样的意思:让sudo执行后面的这些“echo ‘1’ > ip_forward”,而实际上是:sudo echo ‘1’ ,执行到这里,shell再把它的执行结果重定向到ip_forward里去!当然是无权限,因为流本身不会随echo那样被sudo“感染”上suid权限!

解决方法是什么?也很简单,就让后面那一串东西搁一起执行:

$sudo sh -c ‘echo 1 > ip_forward’

等等,还有没有更好的解决方法?有!刘洋同学认真思考了一下,觉得应该有这么个东西XX: echo ‘1’ | sudo XX ip_forward。我擦亮眼睛一看,我靠,这不就是tee(1)么!!没错,另一种解决方法就是:

$echo ‘1’ | sudo tee ip_forward

或者:

$echo ‘1’ | sudo tee ip_forward | cat > /dev/null

刘洋问tee(1)是不是和tea有关系?不是!tee其实取自大写字母T的发音,而T不正是最后一个命令中流的流向么?!多么形象的名字啊!

唐磊-我们的歌

数星星,数星星
我在思念你
不怕风不怕雨
有我陪着你
数星星,数星星
不要再担心
啦啦啦啦啦啦我永远爱你
我的兄弟这首歌曲你还记得吗
那些情景那些回忆都历历在目啊
你总喜欢在宿舍墙上乱抹乱画
你总喜欢在夜深人静时一个人弹着guitar
我的兄弟那段岁月你还记得吗
那些往事回想起来就好像昨天一样
你总喜欢在点名时候让我帮你应答
你总喜欢穿着破洞的牛仔在女生楼下溜达
我的兄弟这些年来你还过的好吗
那个女孩你深爱的还和你在一起吗
记得你曾说过将来一定会娶她
告诉你吧其实我也曾经暗恋过她
我的兄弟这些年来你变得坚强了么
你曾说过梦想是一朵含苞待放的花
好想回去再和你一起高声的歌唱
唱那首歌曲那段旋律唱我们的青春哪

———————-华丽的分割线———————-

很喜欢这首歌,送给所有的好哥们~!!

不知道俺下次再回学校时能否和兄弟们一起去K这首歌??

再来一些shell技巧

1. 批量删除某些指定文件

我们都知道用find,很快就可以给出:

find . -name ‘your_pattern*’ -exec rm -f {} ;

恩,不过还有更快更简洁的方法,用find自带的delete:

find . -name ‘your_pattern*’ -delete

2. 列出当前目录下的所有目录(不递归)

你能想到几种方法?我这里有三种解决方法:

(1) $ ls -l | egrep ‘^d’

(2) $ find . -maxdepth 1 -type d

(3) $ ls -d */.

最后一个是从别处看来的,很巧妙。欢迎提供其它不同的方法。

3. 打印文件的倒数第N行

以倒数第2行为例,我的通常做法是:

$ tail -2 my_file | head -1

另一种方法是:

$ gawk ‘BEGIN {RS = “none_existed_pattern”; FS = “n”}; END {print $(NF-2)}’ my_file

[注:在一些awk(不是gawk)中,RS应该是一个字符,而不能是正则表达式。]

4. 产生连续的数字

常见的方法是用seq:

比如产生1~10的数字,

$ seq 1 10

其实也可以用:

$ echo {1..10}

倒叙时这样:

$ seq 10 -1 1

或者:

$ echo {10..1}

用seq的好处是可以指定步长,但它只能针对数字; {..}虽然不能指定步长,但可以适用于字母。另外,很明显,seq的分隔符是n,而{..}是空格。

5. *grep

你最常用的很可能是grep,可是除此还有两个grep:fgrep和egrep。fgrep是Fixed grep的缩写,而不是fast grep,事实上,搜索同样的字符串时fgrep通常比grep要慢;egrep是Extended grep的所写,因为它采用了扩展的正则表达式和更好的算法,所以你应该更倾向于用egrep而不是grep。

题外话:有多少人知道grep是什么缩写?我也是最近才知道的,它其实是Global Regular Expression Print的缩写,ms也有人说是Get Regular Expression And Print。grep如此常用,以至于连词典都把它收录为一个单词了。

[Jargon File]
grep

/grep/ vi. [from the qed/ed editor idiom g/re/p, where re stands for a regular expression, to Globally search for the Regular Expression and Print the lines containing matches to it, via Unix grep(1)'] To rapidly scan a file or set of files looking for a particular string or pattern (when browsing through a large set of files, one may speak ofgrepping around’). By extension, to look for something by pattern. “Grep the bulletin board for the system backup schedule, would you?” See also vgrep.

最近看的几部电影

《苹果》:很黄。不过那不重要,重要的是这部影片的主题,深刻反映了底层人民无奈的生活,现实对他们来说太残酷了,或许只能无奈地接受。正如其英文名字:Lost in Beijing。

《电锯惊魂 4》:很暴力。我一直很喜欢《电锯惊魂》这部电影,从1一直看到4。别说我变态,看这部电影能让你认真地思考人生的意义!虽然里面的男主角使用了一种极端的手段去强迫麻木的人们去重新认识生命的意义,但回过头来想一想:是不是人类都是只有在失去后才知道珍惜? 有句话说得好,“死亡教会人一切,如同考试之后公布的结果——虽然恍然大悟,但为时晚矣!”别以为活着是理所当然,别以为你拥有的一切都是应该的,趁着自己还活着,好好珍惜,赶快去生活吧!

《当幸福来敲门》:很好。里面的一句话印象很深刻,“You got a dream, you gotta protect it. People can’t do something themselves, they wanna tell you that you can’t do it. You want something? Go get it. Period.” 保卫自己的梦想,然后努力去实现梦想,这是我们都应该学会的。

《我是传奇》:很强大。也是威尔-史密斯主演的,给我最大的感受是:如果地球上只剩你一个人,你还有勇气活下去吗?

《不能说的秘密》:很浪漫。故事情节不错,很浪漫的爱情故事。可现实是:现实远没有那么浪漫。

《大电影2.0》:很凑合。里面的一句话还算经典:“人至贱则无敌,我们就是三贱客呀!”

《投名状》:很没意思。借用网上那句经典的评价一下:“男人不可靠。”

《集结号》:很无聊。战斗场面拍得还不错,可惜故事情节老套,从开头差不多就能猜到结局。

splice(2) considered useful?

无意中发现Linux还有splice(2)这么个玩意儿,而且Linus本人对其很是赞赏,还一门心思地给它做广告……那我们就来看看它到底是何方神圣。

splice(2)绝对比我想象中要难以理解,一开始以为它的功能和dup2(2)差不多,然后觉得不对,似乎和sendfile(2)差不多,后来发现也不对!(否则还加这么一个系统调用干嘛?!)它和sendfile(2)的差别还算是比较大的,后面我们会细谈。

splice(2)这东西,其实它的名字就已经告诉我们它是做什么的了,可因为它牵扯到了pipe,所以就变得不好理解了。我们知道,Unix里的pipe有两端,一个写另一个读。我们通常都用pipe来实现进程间的fifo通信。而splice却用pipe来连接一些东西,所以,它名字就可以告诉我们,它是用来把其它fd和pipe的某一端拼接到一起的!也就是说,splice(2)的两个fd参数中必须有一个是pipe的一端,否则就会产生EINVAL。而且,当某个fd是pipe一端时,其对应的offset pointer必须是NULL。而且而且,splice(2)不会block,读不到数据时它会返回0。还有一点格外重要,一定要注意数据流动的方向,splice(2)对这个方向是很敏感的。

我们可以看出,splice(2)和dup2(2)语意差别显著,并且,当调用两次splice(2)把pipe两端连接到两个其它文件时,其功能就等价于sendfile(2),都是zero copy。进一步思考,其实splice(2)控制的是某个不可见的buffer,而dup2(2)和sendfile(2)控制的都是文件本身。

wikipedia上也有对splice(2)的解释),不怎么详细,里面给的例子还可以,我对着它做了改进,算是用splice(2)实现了sendfile(2)的功能,代码见下。

注意1:LWN上的这篇文章过时了,不用看了。

注意2:man pages里对splice(2)原型的描述是错的!那两个表示offset的参数的类型都应该是loff_t,而不是off_t!我已经做了一个补丁提交给man pages的维护者。

补丁:http://wangcong.org/down/man-2-splice-loff_t.diff

代码:http://wangcong.org/down/splice_copy.c

进一步学习git

以前仅仅掌握了git的基本用法,对git里的很多概念还是不清楚。鉴于使用git之频繁,今天决定仔细学习一下git。

简单地搜了一下,发现中文的似乎就没有很深入介绍git的,都是一些基本的东西。英文教程中,最好的当然是kernel.org官方的教程,一篇详细介绍了git的概念,可以在这里得到;另一篇介绍了一些更核心的东西,在这里

git里有两个强悍的东西,一个是object database,一个是index file。先看前面那个,所谓object database就是存放所有object的一个“数据库”,其实就是.git/objects,里面放的东西自然都是object。git里的object分四种类型:tree,blob,commit,tag。所有的object都有各自的“编号”,叫ref,就是你每次git-log时看到的里面那长长的16进制数字,比如下面这个:

$ git log
commit 03bbe082cffc4533f6557bf23f0c672307067246
Merge: 3047290… fb49161…
Author: Linus Torvalds <>
Date: Thu Jan 17 15:50:19 2008 -0800

这个object的类型显然是commit。这个数字是怎么来的呢?其实就是对object的内容,时间,作者等信息进行SHA1之后得到的。如果你上网络安全课没有睡着的话,你应该知道,这玩意儿其实是为了保证数据的完整性。这样一来保证了不同的object的“编号”不会相同,二来保证了object内容和其它信息的完整。

我们再继续看那四个类型,commit刚才已经看到,它其实就是表示对文件的修改。而一个文件的内容被称为blob,一个目录的状态被称作tree。由此可见,commit是基于tree的,它引用它的parent,表示从这个parent这个tree到历史上另一个tree的“过程”。git-cat-file可以帮助我们查找某个object的类型,或者查看它的内容。而git-ls-tree可以帮我们查看tree的内容。tag object是一个包含tag的object,而tag通常是一个指向某个tag object或commit object的ref,所以我们可以在.git/refs里看到tags。再多说一句,在commit里面,HEAD恐怕是最有名的一个了。;-)

好了,我们再接着看index file。这又是个什么东西呢?也很简单,它其实是个“子虚乌有”的东西,当你对tree里的东西做了修改后,你可以git-diff查看修改,而当你再git-add之后,不带任何参数的git-diff就查不到结果了,因为修改都放到index file里去了!index file又是实实在在存在的,它在.git/index里,以二进制的形式存放。再回头来看,不带任何参数的git-diff其实比较的是index file和当前目录内容的差异。你git-commit一次其实就是把一次git-add的内容加入历史,而git-commit -a才是把所有git-add的结果加入。

还有什么不明白的呢?恩,head,注意,这个是小写,和上面提到的大写的那个不同。head其实应该是指某个ref,不信你看.git/refs/heads。为什么这里是叫heads呢?因为一个branch一个head,branch可能有多个,heads自然就是复数了。一般我们的heads里都有个master,看看它的内容,其实就是一个ref。

这样我们就对git里的概念有了个大体了解了,至少不至于连git的man pages都看不懂了。