Я пытаюсь понять, как переключатель оператор работает в сборке, и я имею следующую программу:переключатель в сборе
int main (int argc, char **argv)
{
int x = argc > 1 ? atoi(argv[1]) : 2;
int y;
switch (x) {
case 0:
y = 0;
break;
case 1:
y = 1;
break;
case 2:
y = 2;
break;
case 3:
y = 3;
// this case "drops through"
case 4:
y = 4;
break;
default:
y = -1;
break;
}
return 0;
}
В сборке он выглядит:
0x804842f <main+19> cmpl $0x1,(%eax)
0x8048432 <main+22> jle 0x804844a <main+46>
0x8048434 <main+24> mov 0x4(%eax),%eax
0x8048437 <main+27> add $0x4,%eax
0x804843a <main+30> mov (%eax),%eax
0x804843c <main+32> sub $0xc,%esp
0x804843f <main+35> push %eax
0x8048440 <main+36> call 0x8048310 <[email protected]>
0x8048445 <main+41> add $0x10,%esp
0x8048448 <main+44> jmp 0x804844f <main+51>
0x804844a <main+46> mov $0x2,%eax
0x804844f <main+51> mov %eax,-0xc(%ebp)
0x8048452 <main+54> cmpl $0x4,-0xc(%ebp)
0x8048456 <main+58> ja 0x8048492 <main+118>
0x8048458 <main+60> mov -0xc(%ebp),%eax
0x804845b <main+63> shl $0x2,%eax
0x804845e <main+66> add $0x8048540,%eax
Мой первый вопрос почему есть ja
инструкция в <main+58>
, а не jg
, так как мы используем целые числа со знаком. И второй вопрос - почему есть сдвиг на 2 бита в <main+63>
, а не какое-либо другое значение.
Это выход 'gcc -O0', правильно? В противном случае это оптимизировалось бы на 'return 0'. Намного интереснее смотреть на * оптимизированный * вывод, создавая функцию, которая возвращает значение, основанное на своих аргументах. [gcc 5.3 -O3] (http://goo.gl/YJBj7D) использует стратегию поиска таблиц для записей, отличных от значений по умолчанию, для реализации 'switch'. Так делает clang 3.7.1. Они улучшали бы код, используя нагрузки «movzx», поэтому записи в таблице должны были быть только 1 байт. Они также не могут воспользоваться тем, что 'x == y' для большинства нестандартных записей, что является проблемой. необычный для этого рисунка. –