Когда мы используем goto * expr;в С? - PullRequest
5 голосов
/ 16 марта 2011
| GOTO '*' expr ';'

Я никогда не видел таких заявлений, кто-нибудь может привести пример?

Ответы [ 6 ]

6 голосов
/ 16 марта 2011

Это так называемое Обозначает значения и представляет собой одно из расширений GCC.


В качестве примера я применил это расширение, чтобы дать ответ на Печать от 1 до 1000 без петель или условий вопрос:

void printMe () 
{
    int i = 1;
    startPrintMe:
    printf ("%d\n", i);
    void *labelPtr = &&startPrintMe + (&&exitPrintMe - &&startPrintMe) * (i++ / 1000);
    goto *labelPtr;
    exitPrintMe:
}
3 голосов
/ 16 марта 2011

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

2 голосов
/ 16 марта 2011

Это специфично для GCC. Это не стандартный C (C89 или C99). (Хотя иногда это может пригодиться, чтобы иметь возможность вычислять goto.)

1 голос
/ 21 мая 2011

Подобно тому, что PrintMe () уже дал, вот мое решение с использованием «таблицы переходов», решающей ту же проблему, за исключением того, что он может выполнять произвольное число операций, в данном случае printf ().Обратите внимание, что ссылочные метки должны быть локальными для функции.

int print_iterate( int count )
{
    int  i=0;

    void * jump_table[2] = { &&start_label , &&stop_label };

  start_label:
    printf( ++i );
    // using integer division: i/count will be 0 until count is reached (then it is 1)
    goto *jump_table[ i/count ]; 

  stop_label:
    return 0;
}
0 голосов
/ 22 октября 2018

Как и другие заявляют, это расширение GNU C (https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html).

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

Несмотря на то, что варианты использования этого немногочисленны, это было бы полезно при написании полностью исключительного ABI на основе C. Исключительный ABI, который я написал для очень унаследованной платформы, использует их для выполнения Longjump без буфера. (Да, я восстановил кадр стека перед раздачей, и я уверен, что переход безопасен).

Кроме того, его можно использовать для блока finally «JSR», как в Java до Java 7, где до возврата сохраняется явная метка возврата, а затем выполняется блок finally. То же самое до того, как какое-либо исключение будет сгенерировано или переброшено (документация ничего не говорит о том, что оно недействительно в GNU C ++, но я, вероятно, вообще не буду использовать его в C ++).

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

0 голосов
/ 21 мая 2011

Никогда.Это не C. Это возможно в «GNU C», но, как прокомментировал Пол, «это одна из худших возможностей FORTRAN», «портированная ... в C», и поэтому должна считаться вредной.

...