Spec-Zone.ru › GCC 15

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

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

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

Чтобы использовать эти значения, нужно иметь возможность перейти по одному из них. Для этого используется оператор вычисляемого перехода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 используется в инициализаторе статической переменной, встраивание и клонирование запрещены.

В отличие от обычного оператора goto, в GNU C++ вычисляемый переход не вызывает деструкторы объектов, выходящих из области видимости.

Сноски

(6)

Аналогичная возможность в Fortran называется assigned goto («присваиваемый goto»), но это название кажется неподходящим для C, где можно не только хранить адреса меток в переменных меток.

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

Spec-Zone.ru

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