Github上翻到下面代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <stdio.h>

enum Name { 
    Name_None = 0, 
    Name_A = 1, 
    Name_B = 2, 
    Name_C = 3, 
};

void foo()
{
    enum Name name = Name_C;

    if (!name == Name_C)    printf("1\n");
    else                    printf("2\n");
}

void bar()
{
    enum Name name = Name_C;

    if (!name == Name_None) printf("1\n");
    else                    printf("2\n");
}

void baz()
{
    enum Name name = Name_None;

    if (!name == Name_A)    printf("1\n");
    else                    printf("2\n");
}

int main() 
{
    foo();
    bar();
    baz();
    return 0;
}

开发者本意是判断name是否等于某个枚举值,但由于运算符!的优先级高过==,表达式中enum转为int处理,对整形int取!的结果是0变为1,非0变为0,所以foobar的输出是对的,而baz的输出是错误的。

这是C语言自身的陷阱之一,没有清晰的规则和约束去减少优先级歧义,让开发者容易犯错。当然这位开发者把!写在开头,胆子也很大,同时下面原因导致他忽略了编译器警告:

  • 习惯
  • 编译选项关掉了此类警告
  • 开发周期短、匆忙地做,而不是做好
  • 维护既有代码时的传染

恰好最近翻到C专家编程,2.3.2谈到有些运算符的优先级是错误的,我也记不住优先级,但见过低级错误的毒打,所以建议做个蠢人,表达式中多使用括号,安心下班做玩具。

说到这,C专家编程有点像剑桥倚天屠龙史,带着读者们来华山围观论剑,书中人物位列五绝。