在switch语句中第一个'case'之前的代码

tur*_*1ng 15 c switch-statement

在C中,可以在第一个case标签之前编写代码.有没有这样做的情况,或者它只是一个"死代码块"?

例如:

switch (...)    {
  {
    int a = 0x2a;
    printf("%d\n", a);
  }
  case 0:
    ...
}
Run Code Online (Sandbox Code Playgroud)

Joe*_*oey 18

我认为这不是一个特征,而是一个关于C如何处理switch/ case只是一系列跳转目标而没有语法限制的工件.这就是为什么Duff的设备可以工作,这也是为什么第一个之前的代码case永远不会运行的原因.

如果查看生成的程序集,您将看到代码将被跳过:

    mov ecx, DWORD PTR _x$[ebp]
    mov DWORD PTR tv64[ebp], ecx
    cmp DWORD PTR tv64[ebp], 0                  ; here begins the switch
    je  SHORT $LN1@main                         ; jump to case 0
    jmp SHORT $LN4@main                         ; jump out of the switch
; Line 8
    mov DWORD PTR _a$752[ebp], 42
; Line 9
    mov edx, DWORD PTR _a$752[ebp]              ; here we have the dead code
    push    edx
    push    OFFSET $SG754
    call    _printf
    add esp, 8
$LN1@main:                                      ; and here case 0
; Line 12
    push    OFFSET $SG756
    call    _printf
    add esp, 4
$LN4@main:
; Line 15
    xor eax, eax
    mov esp, ebp
    pop ebp
    ret 0
Run Code Online (Sandbox Code Playgroud)


Mic*_*urr 12

C标准文档有一个示例可以准确解释此类构造的行为(6.8.4.2/7"switch语句"):

示例在人工程序片段中

switch (expr)
{
    int i = 4;
    f(i);
case 0:
    i  =  17;
    /*  falls through into default code  */
default:
    printf("%d\n", i);
}
Run Code Online (Sandbox Code Playgroud)

标识符i存在的对象具有自动存储持续时间(在块内)但从未初始化,因此如果控制表达式具有非零值,则对printf函数的调用将访问不确定的值.同样,无法访问函数调用f.

因此,尽管这是允许的,但很容易就是其中之一"仅仅因为你不能意味着你应该"的情况.该构造令人困惑,并且很容易导致使用未初始化的变量,因为可能很不清楚初始化是否发生以及发生在何处.


caf*_*caf 11

声明范围仅限于switch块的变量可能很有用(但请注意,将跳过这些变量的任何初始化器):

switch (...)
{
    int n;

    case 0:
    ...
}
Run Code Online (Sandbox Code Playgroud)

从理论上讲,您也可以将代码放在那里使用goto.

  • @ Arc676这是一种常见的误解,即使在有经验的程序员中也是如此.它始于Dijkstra的一篇好文章,但正如Steele在"揭穿'昂贵的程序调用'神话"中指出的那样,goto本身并不坏,但滥用goto是.斯蒂尔:"[W]试图通过禁止构造来消除不必要的概念和编程风格." Goto可以很好地使用,但最好使用非常谨慎.正如他所指出的,如果充分滥用,其他控制结构可用于编写混淆代码.最重要的是避免混淆代码(用goto轻松编写),而不是简单地转到自己. (3认同)
  • @Martin:变量声明*do*工作,因为它们不产生任何输出代码; 他们只是让编译器注意到"啊,我知道这个变量,我已经看到了它". (2认同)