switch语句中第一个“case”之前的代码

t5zmwmid  于 2023-01-25  发布在  其他
关注(0)|答案(4)|浏览(195)

在C语言中,可以在第一个case标签之前编写代码。在某些情况下,这样做是有用的,或者它只是一个"死代码块"?
例如:

switch (...)    {
  {
    int a = 0x2a;
    printf("%d\n", a);
  }
  case 0:
    ...
}
kupeojn6

kupeojn61#

我认为这与其说是一个特性,不如说是C如何处理switch/case的一个工件--仅仅是一系列没有语法限制的跳转目标。这就是Duff's device工作的原因,也是第一个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
1yjd4xko

1yjd4xko2#

C标准文档中有一个示例,它准确地解释了这种类型的构造的行为(6.8.4.2/7“开关语句”):
示例:在阿尔蒂程序片段中

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

标识符为i的对象以自动存储持续时间存在(在块内),但从未初始化,因此如果控制表达式具有非零值,则对printf函数的调用将访问不确定值。类似地,对f函数的调用不能到达。
因此,即使这是允许的,这也很容易成为“你能并不意味着你应该”的情况之一。这种构造很容易混淆,并且很容易导致使用未初始化的变量,因为初始化是否发生以及在哪里发生是非常不清楚的。

nqwrtyyt

nqwrtyyt3#

声明作用域限于switch块的变量可能很有用(但要注意,这些变量的任何初始化器都将被跳过):

switch (...)
{
    int n;

    case 0:
    ...
}

理论上,您还可以将使用goto获得的代码放在那里。

j8yoct9x

j8yoct9x4#

我不明白你的目的。为什么不把密码放在案子之前?

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

这不正是您想要的吗?(除了在您的示例中,如果编译器不抱怨,代码将永远不会运行。)

相关问题