Вопрос об GCC Optimizer и почему этот код всегда возвращает 42? - PullRequest
0 голосов
/ 08 февраля 2019

Недавно я столкнулся с ошибкой, когда переменная была инициализирована внутри оператора switch.Я начал больше играть с этим и понял, что не знаю, что GCC пытается сделать в некоторых из этих оптимизаций.

Учитывая этот код:

int main(int argc, char** argv) {
       switch (argc) {
               case 1000: return 42;
               int y = 24;
               default: return y;
       }
       return argc;
}

Сгенерированный код всегда возвращает 42. Что происходит?Почему int y = 24 все портит?

$ gcc -Wall -Werror -O2 -c test.c
$ objdump -drwCS -Mintel test.o

testo.o:     file format elf64-x86-64

Disassembly of section .text.startup:

0000000000000000 <main>:
   0:   b8 2a 00 00 00          mov    eax,0x2a
   5:   c3                      ret

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

Случаи в switch должны рассматриваться как ярлыки.Если мы переведем ваш код в эквивалентное goto-spaghetti, это может быть проще для понимания:

int main(int argc, char** argv) 
{
  if(argc == 1000) 
    goto label_1000;
  else 
    goto label_default;

  label_1000: return 42;

  int y = 24;

  label_default: return y;

  return argc;
}

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

Поэтому при объявлении переменных внутри коммутаторов всегда рекомендуется использовать составной оператор для каждого случая:

case 1000:
{
  int y = 24;
  break;
}

Помимо предотвращения ошибок спагетти, это также уменьшаетобласть действия переменной для конкретного case.

0 голосов
/ 08 февраля 2019
int main(int argc, char** argv) {
    switch (argc) {
        case 1000: return 42;
        int y = 24;
        default: return y;
    }
    return argc;
}

Чтобы объяснить это немного подробнее, коммутатор точно не выполняет линейную прогрессию.Логическим эквивалентом этого будет:

"Если argc равен 1000, вернуть 42. В противном случае вернуть y"

. int y = 24; никогда не используется, поскольку оно никогда не достигается, компилятор может оптимизировать этои UB в случае значения по умолчанию может также вернуть 42.

Чтобы исправить это и вести себя так, как я подозреваю, вы намерены, вам просто нужно объявить y вне коммутаторазаявление.

int main(int argc, char** argv) {
    int y = 24;
    switch (argc) {
        case 1000: return 42;
        default: return y;
    }
    return argc;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...