6.3 Метки как значения
Вы можете получить адрес метки, определенной в текущей функции (или содержащей функции), с помощью унарного оператора ‘&&’. Значение имеет тип void *. Это значение является константой и может быть использовано там, где допустима константа соответствующего типа. Например:
void *ptr;
/* … */
ptr = &&foo;
Для использования этих значений необходимо уметь переходить по ним. Это делается с помощью оператора вычисленного перехода3, 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 используется в инициализаторе статической переменной, встраивание и клонирование запрещены.
Примечания
Аналогичная функция в Fortran называется назначенным переходом, но это название кажется неподходящим в C, где можно сделать больше, чем просто сохранить адреса меток в переменных меток.
Далее: Вложенные функции, Предыдущее: Локальные метки, Вверх: Расширения C [Содержание][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-7.5.0/gcc/Labels-as-Values.html