Spec-Zone.ru › GCC 14

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

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

Spec-Zone.ru

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