今天给学生讲C语言的switch语句,这总是最难讲的一个控制结构。
 
结构化程序设计试图把典型的跳转模式总结成一个结构,并赋予抽象的逻辑意义,然而这些跳转模式并不能完全概括所有合理的跳转,有时候我们不得不求助于goto
 
每个语言都有实现这些结构的具体办法,当程序正确的时候,我们也许可以按照抽象的意思去理解那些结构。然而,当程序错误的时候,或者就要凭借对具体实现的理解才可能发现错在哪里,这也是大多数结构化过程式语言的问题,你并不能完全抽象。
 
对具体实现的理解就导致程序员为结构不能概括的跳转寻求一些奇怪的写法,这些写法虽然用的是结构化语句,然而却不能用抽象的意思去理解,C语言的switch也许把这种用法推向极致,事实上switchgoto还要离谱,goto语句虽然可以任意跳转,毕竟它还是静态的,而switch实际上是一种动态的goto,它的跳转目的只有在运行时确定。更为随意的是,C语言的跳转语句可以从语句块外面跳入,这确实是其他高级语言少有的,如果你这样做就会导致那些被跳入的控制结构失去原有的抽象意义。
 
我们看看这样的一个分情跳转模式:当几种情形需要分别单独处理一部分,然后共同处理其余部分,这个用switch并不能简单做到,分割单独处理部分的break会跳出switch而掠过了共同处理的部分,我们不得不设定一些标志,这是结构化极端分子经常使用的办法。
switch ( e ) {
    case 1: do_1; break;
    case 2: do_2; break;

    case 3: do_3; common_345; break;
    case 4: do_4; common_345; break;
    case 5: do_5; common_345; break;
}
不用标志的话就只好把common_345重复写。然而C语言switch作为goto的实现允许我们把分割单独部分的break捕捉起来,不让switch看到,方法就是用同样对break敏感的那些循环语句:
switch ( e ) {
    case 1: do_1; break;
    case 2: do_2; break;

    for (;;) {
        case 3: do_3; break;
        case 4: do_4; break;
        case 5: do_5; break;
    }
    common_345;
    break;
}
如果你需要更迷惑人的写法,那么还可以设想一些其他可以分割代码的结构,其中else就是这样的东西,它会挡住if部分:
switch ( e ) {
    case 1: do_1; break;
    case 2: do_2; break;

    if ( 0 )
        case 3: do_3;
    else if ( 0 )
        case 4: do_4;
    else
        case 5: do_5;
    common_345;
    break;
}
这下就更不能从所谓抽象意义去理解那些if语句了。结构化程序的初衷是好的,不过显然他没有解决所有跳转问题,有时还必须诉诸低层的实现来调试错误,试图在低层次理解它的副作用就是带来一些过于灵活的应用。