метки как значения против оператора switch - PullRequest
4 голосов
/ 05 ноября 2011

Я недавно прочитал о метках как значениях,

int main(){
    int value  = 2;
    const void *labels[] = {&&val_0, &&val_1, &&val_2};
    goto *labels[value];
    val_0:
        printf("The value is 0\n");
        goto end;
    val_1:
        printf("The value is 1\n");
        goto end;
    val_2:
        printf("The value is 2\n");
        goto end;
    end:
    return(0);
}

Я спрашиваю о том, есть ли какой-то выигрыш в производительности при использовании этого метода вместо оператора switch или массива указателей?

Ответы [ 5 ]

5 голосов
/ 05 ноября 2011

Это нестандартное расширение, оно, вероятно, будет работать не лучше, чем эквивалентный оператор switch в этом случае, и, IMHO, его следует избегать.Оператор switch более понятен и более удобен в обслуживании.

(Я быстро протестировал свою версию gcc, и она произвела точно такой же код как для этого кода, так и для эквивалента оператора switch. Однако это не был репрезентативный тесттак как он оптимизировал все, кроме фактически выбранного пути к коду.)

Одним из потенциальных факторов производительности является то, что оператор switch должен иметь разумное поведение, даже если value не находится в правильном диапазоне, ваша версия не определенаповедение, поэтому компилятор может избежать проверки диапазона в некотором коде.

3 голосов
/ 05 ноября 2011

Ответ лежит в ассемблерном коде, сгенерированном gcc (-g и -O2).Две функции принимают value в качестве аргумента, который сначала запрашивается у пользователя (чтобы gcc не удалял неиспользуемые фрагменты кода - иначе говоря, удаление мертвого кода ).Конечно, часть printf одинакова для обеих функций и оптимизирована для gcc (обе), поэтому она возвращается сразу после печати.Таким образом, значительная часть - начало обеих функций.Давайте посмотрим на них:

  • Функция перехода:
0x080484d0 <+0>:    push   %ebp                      # -
0x080484d1 <+1>:    mov    %esp,%ebp                 #  |- standard prologue
0x080484d3 <+3>:    sub    $0x28,%esp                # -
0x080484d6 <+6>:    mov    0x8(%ebp),%eax            # get argument
0x080484d9 <+9>:    movl   $0x80484f8,-0x14(%ebp)    # set up labels array
0x080484e0 <+16>:   movl   $0x8048510,-0x10(%ebp)
0x080484e7 <+23>:   movl   $0x8048528,-0xc(%ebp)
0x080484ee <+30>:   jmp    *-0x14(%ebp,%eax,4)       # jump to appropriate sect.
0x080484f2 <+34>:   lea    0x0(%esi),%esi
  • Функция переключения:
0x08048470 <+0>:    push   %ebp                      # -
0x08048471 <+1>:    mov    %esp,%ebp                 #  |- standard prologue
0x08048473 <+3>:    sub    $0x18,%esp                # -
0x08048476 <+6>:    mov    0x8(%ebp),%eax            # get argument
0x08048479 <+9>:    cmp    $0x1,%eax
0x0804847c <+12>:   je     0x80484b8 <switchFunc+72> # jump here if value == 1
0x0804847e <+14>:   cmp    $0x2,%eax
0x08048481 <+17>:   je     0x80484a0 <switchFunc+48> # if value == 2
0x08048483 <+19>:   test   %eax,%eax
0x08048485 <+21>:   jne    0x804849b <switchFunc+43> # if value != 0 return

Оба фрагментаесть «медленная часть»: первый тратит большую часть времени на настройку массива меток, а второй медленный, решая, какой путь выбрать.Так что, по сути, время их выполнения почти одинаково.
Какой из них лучше?Второй, с конструктом switch.Это стандарт С, гораздо более читаемый, понятный и понятный.

3 голосов
/ 05 ноября 2011

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

Лучше всего использовать метку в качестве значения в интерпретаторе многопоточного кода:

Метки в функции переводчика могут быть сохранены в многопоточный код для сверхбыстрой отправки.

2 голосов
/ 05 ноября 2011

Однако эффективная компиляция switch остается открытой проблемой, см., Например, эта бумага .

И хотя label как значения и косвенные goto -s действительно являются расширением языка GCC, оно было принято другими компиляторами (icc, LLVM / clang) и действительно полезно (и является низким функция уровня, в духе C), особенно для кодирования многопоточных интерпретаторов кода, автоматов и т. д. Я не знаю, почему это расширение не становится стандартом (я думаю, оно не стандартизировано из-за социальных или экономических факторов, не из-за технической ненужности.).

0 голосов
/ 05 ноября 2011

Вот документация по этой функции из руководства gnu gcc. http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...