Код перед первым «регистром» в выражении switch - PullRequest
15 голосов
/ 20 января 2010

В C возможно написать код перед первой case меткой. Есть ли случаи, для которых полезно это сделать, или это просто «мертвый блок кода»?

например:.

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

Ответы [ 4 ]

18 голосов
/ 20 января 2010

Я думаю, что это не особенность, а артефакт того, как C обрабатывает switch / case - просто серию прыжковых целей без ограничений по синтаксису. Вот почему устройство Даффа работает, и поэтому код, предшествующий первой 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
12 голосов
/ 20 января 2010

В стандартном документе 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);
}

объект с идентификатором i существует с автоматической продолжительностью хранения (внутри блока), но никогда не инициализируется, и, таким образом, если управляющее выражение имеет ненулевое значение, вызов функции printf получит неопределенное значение , Аналогично, вызов функции f не может быть достигнут.

Так что, хотя это разрешено, это легко одна из тех ситуаций "только потому, что вы можете, а не значит, что вы должны". Конструкция сбивает с толку и может легко привести к использованию неинициализированной переменной, так как может быть очень неясно, происходит ли инициализация и где это происходит.

11 голосов
/ 20 января 2010

Может быть полезно объявить переменные, область действия которых ограничена блоком switch (но следует помнить, что любые инициализаторы для этих переменных будут пропущены):

switch (...)
{
    int n;

    case 0:
    ...
}

Теоретически, вы также можете поместить туда код, который вы используете, используя goto.

1 голос
/ 20 января 2010

Я не понимаю, что вы после.Почему бы просто не поставить код перед делом?

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

Разве это не то же самое, что вы намереваетесь?(кроме вашего примера, код никогда не будет работать, если компилятор не будет жаловаться.)

...