Подтвердить что ты не робот

Почему GCC определяет унарный оператор '&&' вместо использования '&'?

Как обсуждалось в этом вопросе, GCC определяет нестандартный унарный оператор &&, чтобы взять адрес метки.

Почему он определяет новый оператор вместо использования существующей семантики оператора & и/или семантики функций (где foo и &foo оба дают адрес функции foo())?

4b9b3361

Ответ 1

Имена ярлыков не мешают другим идентификаторам, потому что они используются только в gotos. Переменная и метка могут иметь одно и то же имя, а в стандартных C и С++ всегда ясно из контекста, что подразумевается. Так что это совершенно верно:

name:
  int name;
  name = 4; // refers to the variable
  goto name; // refers to the label

Различие между и и && так что компилятор знает, какое имя ожидать:

  &name; // refers to the variable
  &&name; // refers to the label

Ответ 2

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

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

Где foo, bar и hack - метки. Затем метку можно выбрать с индексированием, например:

goto *array[i];   

Стандарт говорит, что

C11: 6.2.1 Области идентификаторов (p1):

Идентификатор может обозначать объект; функция; тег или член структуры, объединения или перечисления; имя typedef; a имя метки; имя макроса; или макропараметр.

Далее говорится в разделе 6.2.3:

Если более чем одно объявление определенного идентификатора видимо в любой точке единицы перевода, синтаксический контекст неоднозначно использует использование, относящееся к различным объектам. Таким образом, существуют отдельные пространства имен для различных категорий идентификаторов, а именно:

- имена ярлыков (неясно, с синтаксисом объявления и использования метки);

- теги структур, объединений и перечислений (неоднозначно следуя любым 32) ключевых слов struct, union или enum);

- члены структур или союзов; каждая структура или объединение имеет отдельное пространство имен для своих членов (неоднозначно по типу выражения, используемого для доступа к элементу через оператор . или ->);

- все остальные идентификаторы, называемые обычными идентификаторами (объявляются в обычных деклараторах или в качестве констант перечисления).

Это означает, что объект и метка могут быть обозначены одним и тем же идентификатором. На этом этапе, чтобы компилятор знал, что адрес foo является адресом метки, а не адресом объекта foo (если существует), GCC определил оператор && для адреса метки.