今年春节期间,我在图灵社区购买了三本电子书,其中一本是《卓越程序员密码》。这本书不厚,正文才158页。阅读过程也很轻松。

作者张家为(Ka Wai Cheung)先生在中文版序中说:

在编程的世界里,我们会和各种各样的“语言”打交道。虽然我主要的服务器端开发语言是C#,但我的工作方法却几乎可以完全应用到Java、PHP、Ruby或Python上。编程语言虽有不同,核心的编程思想、方法和架构却是高度类似的。我们只是用不同的方式来表达而已。

正好我目前主要也使用 C# 语言,兴趣相投。我最初接触计算机时学的是 PASCAL 语言。第二门语言是 C 语言,读的是经典的 K&R 的《C程序设计语言》,当时还是第一版。以后逐渐学习了 C++ 语言。现在全面转向 C# 语言,而且对 Linux 操作系统下的 Mono 很有兴趣。

《卓越程序员密码》由 50 篇短小精悍的文章组成。在阅读过程中,很多话题都能引起我的会心一笑。比如第 30 篇谈到为电梯设计软件,要求要让人们呆在电梯里的总时间最短。这个目标是非常难以实现的,而且还是没有什么回报的复杂性,这就是一个难编就意味着难用的例子。传统的电梯算法既简单,又好用。

在第 47 篇“代码是最好的初级程序员”中,作者给出了一个 C# 程序的代码片段:

public int sum_range_of_positive_integers_to_100()
{
     int sum;

     for (int i = 1; i <= 100; i++)
     {
         sum += i;
     }

     return sum;
}

这段代码用来计算从 1 加到 100 得多少。但是这段代码是有问题的,使用 C# 编译器编译时会报告以下错误:

error CS0165: Use of unassigned local variable `sum'

这种局部变量未初始化的情况是初学者很容易犯的错误,作者在这里也粗心了。还好 C# 编译器会帮助我们避免这种错误。
如果是 C 语言,就没这么幸运了,编译会通过,但运行结果很可能就不正确了。还好,有个 splint 工具也可以帮助我们:

Splint is a tool for statically checking C programs for security vulnerabilities and coding mistakes.

假设我们有以下 C 语言程序:

#include <stdio.h>

int main()
{
  int sum;
  printf("%d\n", sum);
  return 0;
}

在 Arch Linux 操作系统中,使用 gcc 编译,再使用 splint 工具检查,结果如下:

work$ gcc a.c && ./a.out
0
work$ splint a.c
Splint 3.1.2 --- 14 Sep 2011

a.c: (in function main)
a.c:6:18: Variable sum used before definition
  An rvalue is used that may not be initialized to a value on some execution
  path. (Use -usedef to inhibit warning)

Finished checking --- 1 code warning

C 编译器一声不吭,而 splint 就报告可能存在问题。

C# 语言规范5.1.7 Local variables 中提到:

A local variable introduced by a local-variable-declaration is not automatically initialized and thus has no default value.

对于 C 语言来说,在 K&R 的经典著作 《C程序设计语言》(第二版)APPENDIX A: Reference ManualA8.7 Initialization 中提到:

The initial value of an automatic object not explicitly initialized is undefined.

从上面的权威资料中可以看出,无论是 C 语言,还是 C# 语言,局部变量不初始化是不行的。

此外,我还给《卓越程序员密码》提了不少勘误,有些已经被图灵社区的编辑确认了,但还有些至今还没有处理。