Как сохранить метки goto в массиве, а затем перейти к ним? - PullRequest
18 голосов
/ 02 июня 2009

Я хочу объявить массив «переходных меток».

Тогда я хочу перейти к «прыжковой метке» в этом массиве.

Но я понятия не имею, как это сделать.

Он должен выглядеть следующим образом:

function()
{
    "gotolabel" s[3];
    s[0] = s0;
    s[1] = s1;
    s[2] = s2;

    s0:
    ....
    goto s[v];

    s1:
    ....
    goto s[v];

    s2:
    ....
    goto s[v];
}

У кого-нибудь есть идеи, как это сделать?

Ответы [ 11 ]

40 голосов
/ 02 июня 2009

Это возможно с функцией GCC, известной как " метки как значения ".

void *s[3] = {&&s0, &&s1, &&s2};

if (n >= 0 && n <=2)
    goto *s[n];

s0:
...
s1:
...
s2:
...

Работает только с GCC!

17 голосов
/ 02 июня 2009

goto нужна метка времени компиляции.

Из этого примера кажется, что вы реализуете какой-то конечный автомат. Чаще всего они реализованы в виде коммутационной конструкции:

while (!finished) switch (state) {
  case s0:
  /* ... */
  state = newstate;
  break;

  /* ... */
}

Если вам нужно, чтобы он был более динамичным, используйте массив указателей функций.

12 голосов
/ 02 июня 2009

Нет прямого способа хранить адреса кода для перехода в C. Как насчет использования switch.

#define jump(x)  do{ label=x; goto jump_target; }while(0)
int label=START;
jump_target:
switch(label)
{
    case START:
        /* ... */
    case LABEL_A:
        /* ... */
}

Вы можете найти похожий код, созданный каждым бессистемным парсером / генератором конечных автоматов. За таким кодом нелегко следовать, поэтому, если это не сгенерированный код или ваша проблема наиболее легко описывается конечным автоматом, я бы рекомендовал не делать этого.

8 голосов
/ 02 июня 2009

не могли бы вы использовать функциональные указатели вместо goto?

Таким образом, вы можете создать массив функций для вызова и вызова соответствующей функции.

6 голосов
/ 02 июня 2009

В простом стандарте C, насколько я знаю, это невозможно. Однако в компиляторе GCC есть расширение , задокументированное здесь , которое делает это возможным.

Расширение вводит новый оператор &&, чтобы получить адрес метки, который затем может использоваться с оператором goto.

5 голосов
/ 02 июня 2009

Вот для чего switch заявления.

switch (var)
{
case 0:
    /* ... */
    break;
case 1:
    /* ... */
    break;
default:
    /* ... */
    break;  /* not necessary here */
}

Обратите внимание, что компилятор не обязательно переводит их в таблицу переходов.

Если вы действительно хотите построить таблицу переходов самостоятельно, вы можете использовать массив указателей на функции.

3 голосов
/ 02 июня 2009

Возможно, вы захотите взглянуть на setjmp / longjmp.

2 голосов
/ 02 июня 2009

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

2 голосов
/ 02 июня 2009

Вы не можете сделать это с помощью goto - метки должны быть идентификаторами, а не переменными или константами. Я не понимаю, почему вы не захотите использовать здесь переключатель - он, вероятно, будет столь же эффективным, если это то, что касается вас.

1 голос
/ 16 апреля 2016

Оптимизирующие компиляторы (включая GCC) скомпилируют оператор switch в таблицу переходов (делая оператор switch точно так же быстро, как то, что вы пытаетесь построить), ЕСЛИ выполняются следующие условия:

Ваши случаи переключения (номера состояний) начинаются с нуля.

Ваши случаи переключения строго увеличиваются.

Вы не пропускаете целые числа в своих случаях переключения.

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

Это дает вам преимущество, заключающееся в том, что вы можете писать свой код в стандарте C вместо того, чтобы полагаться на расширение компилятора. Это будет работать так же быстро в GCC. Он также будет работать так же быстро в большинстве оптимизирующих компиляторов (я знаю, что это делает компилятор Intel; не уверен насчет вещей Microsoft). И это будет работать, хотя и медленнее, на любом компиляторе.

...