Я думаю, что ответ на ваш вопрос о том, почему это так, основан на двух вариантах поведения, оба из которых связаны с созданным кодом сборки из источника C.
Во-первых, в сборке выполняется текущая инструкция, и, если не будет перехода или какой-либо другой инструкции управления потоком, будет выполнена инструкция по следующему адресу. Выполнение простой компиляции оператора switch в ассемблере сгенерирует код, который просто начнет выполнять первую инструкцию, которая будет проверять, есть ли соответствующее условие ...
Второй связанной причиной является понятие таблицы ветвлений или списка переходов . По сути, компилятор может взять то, что он знает о вашей ценности, и создать для этой цели очень эффективный машинный код. Возьмем, к примеру, простую функцию типа atoi, которая преобразует строковое представление числа и возвращает его в целочисленной форме. Упрощая вещи, поддерживая только одну цифру, вы можете написать код, подобный следующему:
int atoi(char c) {
switch (c) {
case '0': return 0;
case '1': return 1;
// ....
}
}
Наивный компилятор, возможно, просто преобразовал бы это в серию блоков if / then, означая, что для числа 9 будет взято значительное количество циклов ЦП, а 0 возвращается почти сразу. Используя таблицу ветвлений, компилятор может выдать некоторую сборку [psuedo], которая немедленно «перейдет» к правильному предложению возврата:
0x1000 # stick value of c in a register
0x1004 # jump to address c + calculated offset
# example '0' would be 0x30, the offset in for this sample
# would always be 0x0FD8... thus 0x30 + 0x0FD8 = 0x1008
0x1008 # return 0
Извинения: мои навыки сборки и C довольно ржавые. Я надеюсь, что это помогает прояснить ситуацию.
0x