Подтвердить что ты не робот

Как сохранить метки goto в массиве, а затем перейти к ним?

Я хочу объявить массив "jumplabels".

Затем я хочу перейти к "jumplabel" в этом массиве.

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

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

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];
}

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

4b9b3361

Ответ 1

Возможно с помощью функции GCC, известной как " метки как значения".

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

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

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

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

Ответ 2

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

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

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

  /* ... */
}

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

Ответ 3

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

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

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

Ответ 4

Можно ли использовать указатели на функции вместо goto?

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

Ответ 5

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

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

Ответ 6

Для чего предназначены switch.

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

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

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

Ответ 7

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

Ответ 8

Возможно, вы захотите посмотреть на setjmp/longjmp.

Ответ 9

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

Ответ 10

Tokenizer? Это похоже на то, что сделал gperf. Нет, взгляните на это.

Ответ 11

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

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

Ваши коммутационные шкафы строго возрастают.

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

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

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