2012-03-30 2 views
2

Из того, что я читал из разных ответов на подобные вопросы, в некоторых случаях случаи переключения скомпилированы по-разному.C++, корпус коммутатора и компилятор

У меня есть несколько сценариев, но я не уверен, как они скомпилируются.

Сценарий 1

Переключатель случай, который принимает значение перечисления. Шкалы варьируются от 0 до 99 и упорядочены.

Сценарий 2

Переключатель случай, который принимает значение перечисления. Шкалы варьируются от let say, 0 - 30, 50 - 80, 100 - 150. Unordered. Будет ли это компилироваться иначе, чем сценарий выше?


В основном я хотел бы знать, как дела коммутатора в сценариях будут составлено, и если какое-либо различие между этими двумя сценариями. Благодаря!

Редактировать: Я должен был упомянуть, что одной из моих самых больших проблем является то, сколько проверок потребуется для соответствия делу. Если операторы линейны, то для сценария один, если это было if-else-если бы это заняло не более 100 проверок, если я не ошибаюсь. Но как это делается с коммутационными шкафами? Какую оптимизацию делает компилятор?

+1

У вас есть 'break' на каждом' случае'? Если нет, то это может изменить ситуацию, если да, я не могу представить компилятор, который не может его оптимизировать, и создает менее оптимальный код для сценария 2, основанный только на порядке меток 'case'. – vsz

+2

До тех пор, пока код логически эквивалентен, бизнес компилятора относится к тому, как он закладывает вещи. Спросите своего компилятора (т. Е. Проверьте его и посмотрите на результат). – Mat

+0

Попробуйте, это не займет много времени, чтобы написать тест для этого. Я подозреваю, что это не имеет значения, если синтаксис правильный. Как и vsz, компилятор будет оптимизировать результат, если вы используете параметр/o. –

ответ

7

Невозможно сказать в общем. В стандарте C++ практически нет предположений о генерируемом коде. Это означает, что компилятор свободен почти (да, есть исключения) переупорядочивает код, если семантика остается прежней. Оптимизацию часто называли «черной магией конструкции компилятора», когда я проходил курсы по этой теме.

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

Единственный способ узнать, что произойдет, это посмотреть на выход компилятора с определенными фиксированными флагами и посмотреть, что произойдет. И как только вы узнаете, что происходит, не полагайтесь на него, это может измениться в следующей версии компилятора.

Если вы программируете, всегда соблюдайте гарантии, которые дает вам стандарт языка, и никогда не предполагайте ничего сверх этого.

0

Похоже, вам просто нужно взглянуть на дизассемблер. Switch действительно очень интересный) Взгляните с оптимизацией и без нее. Have a fun =)

2

Большинство компиляторов скомпилируют их по-разному. Но это полностью зависит от компилятора и архитектуры.

4

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

Для менее полной версии компилятор должен балансировать таблицу перехода и инструкции ветвления. Вероятно, это будет зависеть и от настроек: увеличьте ли вы максимальную скорость с -O3 или минимизируйте размер с помощью -Oz, чтобы повлиять на некоторые кромки.

Наконец, коммутатор имеет только один корпус, он, скорее всего, будет представлен как ветка.

Наличие break или провал не сильно влияет на ситуацию. Сборка определяется в терминах меток, и как break, так и пассаж естественно представлены, поэтому не должны влиять на использование ветвей или таблиц прыжков.


Demo (с использованием Попробуйте сайт LLVM)

enum Enum { 
    Zero, 
    One, 
    Two, 
    Three, 
    Four, 
    Five, 
    Six, 
    Seven, 
    Eight, 
    Nine 
}; 

char const* full(enum Enum e) { 
    switch(e) { 
    case Zero: return "Zero"; 
    case One: return "One"; 
    case Two: return "Two"; 
    case Three: return "Three"; 
    case Four: return "Four"; 
    case Five: return "Five"; 
    case Six: return "Six"; 
    case Seven: return "Seven"; 
    case Eight: return "Eight"; 
    case Nine: return "Nine"; 
    } 

    return "Uh ?"; 
} 

char const* sparse(enum Enum e) { 
    switch(e) { 
    default: return "Not handled"; 
    case Zero: return "Zero"; 
    case One: return "One"; 
    case Two: return "Two"; 
    case Seven: return "Seven"; 
    case Eight: return "Eight"; 
    case Nine: return "Nine"; 
    } 
} 

char const* null(enum Enum e) { 
    switch(e) { 
    default: return "Not Zero"; 
    case Zero: return "Zero"; 
    } 
} 

Функция full компилируется:

.text 
    .globl full 
    .align 16, 0x90 
    .type full,@function 
full:         # @full 
.Ltmp0: 
    .cfi_startproc 
# BB#0: 
    cmpl $9, %edi 
    ja .LBB0_11 
# BB#1: 
    movl %edi, %ecx 
    movl $.L.str, %eax 
    jmpq *.LJTI0_0(,%rcx,8) 
.LBB0_2: 
    movl $.L.str1, %eax 
    ret 
.LBB0_3: 
    movl $.L.str2, %eax 
    ret 
.LBB0_4: 
    movl $.L.str3, %eax 
    ret 
.LBB0_5: 
    movl $.L.str4, %eax 
    ret 
.LBB0_6: 
    movl $.L.str5, %eax 
    ret 
.LBB0_7: 
    movl $.L.str6, %eax 
    ret 
.LBB0_8: 
    movl $.L.str7, %eax 
    ret 
.LBB0_9: 
    movl $.L.str8, %eax 
    ret 
.LBB0_10: 
    movl $.L.str9, %eax 
    ret 
.LBB0_11: 
    movl $.L.str10, %eax 
.LBB0_12: 
    ret 
.Ltmp1: 
    .size full, .Ltmp1-full 
.Ltmp2: 
    .cfi_endproc 
.Leh_func_end0: 
    .section .rodata,"a",@progbits 
    .align 8 
.LJTI0_0: 
    .quad .LBB0_12 
    .quad .LBB0_2 
    .quad .LBB0_3 
    .quad .LBB0_4 
    .quad .LBB0_5 
    .quad .LBB0_6 
    .quad .LBB0_7 
    .quad .LBB0_8 
    .quad .LBB0_9 
    .quad .LBB0_10 

И функция sparse к:

.text 
    .globl sparse 
    .align 16, 0x90 
    .type sparse,@function 
sparse:         # @sparse 
.Ltmp3: 
    .cfi_startproc 
# BB#0: 
    movl $.L.str11, %eax 
    cmpl $9, %edi 
    ja .LBB1_8 
# BB#1: 
    movl %edi, %ecx 
    jmpq *.LJTI1_0(,%rcx,8) 
.LBB1_2: 
    movl $.L.str, %eax 
    ret 
.LBB1_3: 
    movl $.L.str1, %eax 
    ret 
.LBB1_4: 
    movl $.L.str2, %eax 
    ret 
.LBB1_5: 
    movl $.L.str7, %eax 
    ret 
.LBB1_6: 
    movl $.L.str8, %eax 
    ret 
.LBB1_7: 
    movl $.L.str9, %eax 
.LBB1_8: 
    ret 
.Ltmp4: 
    .size sparse, .Ltmp4-sparse 
.Ltmp5: 
    .cfi_endproc 
.Leh_func_end1: 
    .section .rodata,"a",@progbits 
    .align 8 
.LJTI1_0: 
    .quad .LBB1_2 
    .quad .LBB1_3 
    .quad .LBB1_4 
    .quad .LBB1_8 
    .quad .LBB1_8 
    .quad .LBB1_8 
    .quad .LBB1_8 
    .quad .LBB1_5 
    .quad .LBB1_6 
    .quad .LBB1_7 

A nd, наконец, функция null:

.text 
    .globl null 
    .align 16, 0x90 
    .type null,@function 
null:         # @null 
.Ltmp0: 
    .cfi_startproc 
# BB#0: 
    movl $.L.str1, %ecx 
    testl %edi, %edi 
    movl $.L.str, %eax 
    cmoveq %rcx, %rax 
    ret 
.Ltmp1: 
    .size null, .Ltmp1-null 
.Ltmp2: 
    .cfi_endproc 
.Leh_func_end0: 
Смежные вопросы