Spec-Zone.ru › GCC 12

6.3 Метки как значения

Вы можете получить адрес метки, определенной в текущей функции (или содержащей функции), с помощью унарного оператора ‘&&’. Значение имеет тип void *. Это значение является константой и может быть использовано везде, где допустима константа такого типа. Например:

void *ptr;
/* … */
ptr = &&foo;

Чтобы использовать эти значения, вам необходимо уметь переходить к ним. Это делается с помощью инструкции computed goto 6, goto *exp;. Например,

goto *ptr;

Допускается любое выражение типа void *.

Один из способов использования этих констант — инициализация статического массива, который служит таблицей переходов:

static void *array[] = { &&foo, &&bar, &&hack };

Затем вы можете выбрать метку с помощью индексирования, как показано ниже:

goto *array[i];

Обратите внимание, что это не проверяет, находится ли индекс в пределах массива — индексирование массивов в C никогда этого не делает.

Такой массив значений меток выполняет функцию, аналогичную инструкции switch. Инструкция switch более удобна, поэтому используйте её вместо массива, если проблема не подходит для использования инструкции switch.

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

Вы не можете использовать этот механизм для перехода к коду в другой функции. Если вы это сделаете, произойдут совершенно непредсказуемые вещи. Лучший способ избежать этого — хранить адрес метки только в автоматических переменных и никогда не передавать его в качестве аргумента.

Альтернативный способ записи предыдущего примера:

static const int array[] = { &&foo - &&foo, &&bar - &&foo,
                             &&hack - &&foo };
goto *(&&foo + array[i]);

Это более удобно для кода, живущего в общих библиотеках, поскольку это уменьшает количество необходимых динамических перемещений и, как следствие, позволяет сделать данные только для чтения. Эта альтернатива с различиями меток не поддерживается для целевой платформы AVR, пожалуйста, используйте первый подход для программ AVR.

Выражения &&foo для одной и той же метки могут иметь разные значения, если содержащая функция интегрирована или клонирована. Если программа полагается на то, что они всегда одинаковы, необходимо использовать __attribute__((__noinline__,__noclone__)), чтобы предотвратить инлайнирование и клонирование. Если &&foo используется в инициализаторе статической переменной, инлайнирование и клонирование запрещены.

Примечания

(6)

Аналогичная функция в Fortran называется assigned goto, но это название кажется неподходящим в C, где можно делать больше, чем просто хранить адреса меток в переменных меток.

Далее: Вложенные функции, Предыдущее: Локальные метки, Вверх: Расширения C [Оглавление][Индекс]

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-12.2.0/gcc/Labels-as-Values.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API