Spec-Zone.ru › GCC 10

Next: Вложенные функции, Previous: Локально объявленные метки, Up: Расширения семейства языков C [Оглавление][Индекс]

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

Примечания

(3)

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

Next: Вложенные функции, Previous: Локально объявленные метки, Up: Расширения семейства языков C [Оглавление][Индекс]

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

Spec-Zone.ru

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