Можно ли использовать значение переменной в качестве метки для перехода goto?

Есть следующий код:

int main() {    
    goto s;
    return 1;
s:
    return 0;
}

Можно ли составить равносильный ему, но вместо фиксированного лейбла s использовать символ?

Псевдокод:

int main() {
    char str = 's';
    goto str;  
    return 1;
s:
    return 0;  
}

Нельзя использовать никакие условные операторы.


Ответы (3 шт):

Автор решения: αλεχολυτ

Читаем стандарт:

8.7.5 The goto statement [stmt.goto]

The goto statement unconditionally transfers control to the statement labeled by the identifier. The identifier shall be a label (8.2) located in the current function.

Оператор goto безусловно передаёт управление инструкции, обозначенной идентификатором. Этот идентификатор должен быть меткой, расположенной в текущей функции.

Соответственно ни о каких переменных в goto речи быть не может. Более того, возможно одновременное существование меток и переменных с одинаковым названием:

#include <iostream>

int main() {
    int p = 42;
    goto p;
    std::cout << "not printed\n";
    p: std::cout << p << "\n";
}

Однако, как подсказали в комментарии, существует GNU расширение, позволяющее использовать метки как значения.

→ Ссылка
Автор решения: avp

В компиляторе от GNU можно.

Только не напрямую, а используя символ в качестве индекса в массиве меток.

#include <stdio.h>

int
main (int ac, char *av[])
{
  void *p[] = {&&L1, &&L2};
  unsigned char c;

  scanf("%c", &c);
  goto *p[c & 1];

 L1:
  printf("'%c' is even code %d\n", c, c);
  goto fin;
 L2:
  printf("'%c' is odd code %d\n", c, c);

 fin:
  return puts("End") == EOF;
}

Транслируем и запускаем

avp@avp-xubu2:~/hashcode$ g++ tf.c
avp@avp-xubu2:~/hashcode$ ./a.out
a       
'a' is odd code 97
End
avp@avp-xubu2:~/hashcode$ ./a.out
b
'b' is even code 98
End
avp@avp-xubu2:~/hashcode$ 

P.S.
извините, но для всех символов мне было лень набивать...

→ Ссылка
Автор решения: MSDN.WhiteKnight

Раз уж зашла речь об извращениях, вот решение для Visual C++ (только x86):

#include <iostream>
#include <map>

std::map<char, void*> labels;
#define GOTO(x) {void* tmp=labels[x];__asm {jmp tmp}}
#define SAVE_LABEL(x,name) {void* tmp;__asm {mov tmp, offset x};labels[name]=tmp;}

int main() {

    SAVE_LABEL(s, 's');
    SAVE_LABEL(p, 'p'); 
    GOTO('p')

    printf("Hello, world!\n");

s:  printf("Hello from s!\n");
    return 1;

p:  printf("Hello from p!\n");
    return 0;
}

Суть способа в том, что хоть goto и не может переходить к переменным, но вот инструкции безусловного перехода, которую он использует, абсолютно наплевать, к чему переходить.

Это приводит нас к такому ассемблерному коду для перехода

__asm {jmp x}

где x - произвольный адрес.

И к такому для получения адреса метки:

__asm {mov x, offset y}

где x - переменная, y - имя метки.

Но тут следует понимать, что ассемблерные вставки непереносимы и мешают компилятору оптимизировать код функции, в которой они присутствуют. Поэтому если вы хотели таким образом состряпать какое-то высокоэффективное решение с таблицами переходов, скорее всего, ничего не выйдет.

→ Ссылка