近日仍在学习Linux编程,可以算是多本书一起看。发现《Beginning Linux Programming》4th书中一处比较严重的错误,比较容易误导C语言初学者。
代码取自Chapter 15:Sockets,英文版625页,片段如下:
1 int main (int argc, char* argv[]) 2 { 3 char *host, 4 **names, 5 **addrs; 6 struct hostent* hostinfo; 7 8 if (argc == 1) 9 { 10 char myname[256]; 11 gethostname(myname, 255); 12 host = myname; 13 } 14 else 15 host = argv[1]; 16 /* 17 */ 18 }
刚看到这段代码,我就感觉到奇怪,这里似乎有错。但我又不是非常确定,后来去stackoverflow上提了个问,看到别人的回复终于认定了我是对的。其实这也是使用局部变量地址的一种比较隐蔽的形式,平时一般都说函数中的变量生存期,而很少注意block中的变量生存期。昨天在图书馆还书的时候,发现这本书的第三版,我顺手拿起来翻阅了一下,发现其第十五章那里同样有这样一段ugly的代码。第三版的错误延续到了第四版,这有点不可原谅。本想发一封邮件给作者提醒一下,后来发觉这本书居然没有致谢,那就算了^_^。
在提问的时候,在问题的comment里,我又学到了一些新的东西。核心思想不过是加强对编译器功能的利用,在早期的c语言书(国内卖的人民邮电出的c&&c++经典书系)中推崇这种写法:
if (1 == argc)
这样写的好处是防止手抖而少写了一个‘=’时,编译器会编译出错,因为‘1’无法作为左值。而把argc放到左边又少写了一个‘=’号会导致逻辑上的重大错误而又难以发现。而后来呢,各路大牛都不这样写了。因为这种写法降低了代码的可读性,因为绝大多数人都已经习惯了从左往右的顺序读代码,当然写代码的时候也是从左往右的。现在比较流行的做法是提升编译器的警告层次,我上次在阅读某大牛的代码时就看到,他的makefile中CFLAGS中有这种片段:
-Werror
而Werror的意思就是,将警告升级为错误:
-Werror Make all warnings into errors.
以前编译代码,一直无视warning,以后得改了。写代码么,就要写出 0 warning的出来。