Spec-Zone.ru › GCC 15

6.4.7 Синтаксис атрибутов

GCC предоставляет два разных способа указания атрибутов: стандартный синтаксис C и C++ с двойными квадратными скобками и старый синтаксис расширения GNU с использованием ключевого слова __attribute__, появившийся до принятия стандартного синтаксиса и до сих пор широко используемый в старом коде.

Стандартный синтаксис атрибутов «[[]]» распознаётся диалектом языка, используемым GCC по умолчанию, как для C, так и для C++. Точнее, этот синтаксис впервые появился в стандарте языка C++11 (см. раздел Поддерживаемые GCC стандарты языков) и поддерживается GCC в коде C++ с параметром -std=c++11 или -std=gnu++11 и более поздними версиями. Он также входит в стандарт языка C23 и поддерживается при компиляции кода C с параметром -std=c23 или -std=gnu17 и более поздними версиями.

При использовании атрибутов, специфичных для GNU, в стандартном синтаксисе необходимо предварять их имена префиксом «gnu::», например gnu::section. Точные сведения о размещении атрибутов «[[]]» в коде см. в соответствующих стандартах языка: некоторые детали этих правил отличаются от правил синтаксиса атрибутов GNU.

При использовании параметра -fopenmp GCC дополнительно распознаёт директивы OpenMP с именами, имеющими префикс «omp::», в стандартном синтаксисе «[[]]». См. раздел OpenMP.

В оставшейся части этого раздела описываются подробности синтаксиса расширения GNU __attribute__ и конструкции, к которым относятся спецификаторы атрибутов, для языка C. Некоторые детали могут отличаться для C++ и Objective-C. Из-за ограничений грамматики атрибутов некоторые описанные здесь формы не всегда удаётся успешно разобрать.

В семантике атрибутов в C++ есть некоторые проблемы. Например, для атрибутов не предусмотрены имена, используемые при манглинге, хотя они могут влиять на генерацию кода; поэтому при использовании типов с атрибутами совместно с шаблонами или перегрузкой могут возникнуть проблемы. Аналогично, typeid не различает типы с разными атрибутами. В будущем поддержка атрибутов в C++ может быть ограничена только атрибутами в объявлениях, но не во вложенных деклараторах.

Сведения о семантике атрибутов, применяемых к функциям, см. в разделе Объявление атрибутов функций. Сведения о семантике атрибутов, применяемых к переменным, см. в разделе Указание атрибутов переменных. Сведения о семантике атрибутов, применяемых к структурам, объединениям и перечислимым типам, см. в разделе Указание атрибутов типов. Сведения о семантике атрибутов, применяемых к меткам, см. в разделе Атрибуты меток. Сведения о семантике атрибутов, применяемых к элементам перечисления, см. в разделе Атрибуты элементов перечисления. Сведения о семантике атрибутов, применяемых к операторам, см. в разделе Атрибуты операторов.

Спецификатор атрибута имеет вид __attribute__ ((attribute-list)). Список атрибутов — это, возможно, пустая последовательность атрибутов, разделённых запятыми, где каждый атрибут имеет одну из следующих форм:

  • Пустой атрибут. Пустые атрибуты игнорируются.
  • Имя атрибута (это может быть идентификатор, например unused, или зарезервированное слово, например const).
  • Имя атрибута, за которым следует заключённый в круглые скобки список параметров атрибута. Эти параметры имеют одну из следующих форм:
    • Идентификатор. Например, атрибуты mode используют эту форму.
    • Идентификатор, за которым следуют запятая и непустой список выражений, разделённых запятыми. Например, атрибуты format используют эту форму.
    • Возможно, пустой список выражений, разделённых запятыми. Например, атрибуты format_arg используют эту форму со списком, состоящим из одного целочисленного константного выражения, а атрибуты alias — со списком, состоящим из одной строковой константы.

Список спецификаторов атрибутов — это последовательность из одного или нескольких спецификаторов атрибутов без каких-либо других токенов между ними.

При желании имена атрибутов можно заключать между двумя «__»: перед именем и после него. Это позволяет использовать их в заголовочных файлах, не опасаясь возможного макроса с тем же именем. Например, можно использовать имя атрибута __noreturn__ вместо noreturn.

Атрибуты меток

В GNU C список спецификаторов атрибутов может следовать после двоеточия за меткой, кроме метки case или default. В GNU C++ атрибуты меток допустимы только в том случае, если сразу за спецификатором атрибута следует точка с запятой (то есть метка относится к пустому оператору). Если точка с запятой отсутствует, атрибуты меток в C++ неоднозначны, поскольку в C++ к метке можно привязать объявление, которое может начинаться со списка атрибутов. В C90 и C99 объявления нельзя помечать метками, поэтому такой неоднозначности там не возникает.

Атрибуты элементов перечисления

В GNU C список спецификаторов атрибутов может входить в состав элемента перечисления. Атрибут указывается после константы перечисления и перед «=», если оно присутствует. Необязательный атрибут элемента относится к константе перечисления. Если константное выражение присутствует, разместить атрибут после него нельзя.

Атрибуты операторов

В GNU C список спецификаторов атрибутов может входить в состав пустого оператора. Атрибут указывается перед точкой с запятой. Некоторые атрибуты в синтаксисе нового стиля также поддерживаются для непустых операторов.

Атрибуты типов

Список спецификаторов атрибутов может входить в состав спецификатора struct, union или enum. Он может располагаться либо сразу после ключевого слова struct, union или enum, либо после закрывающей фигурной скобки. Предпочтителен первый вариант. Если спецификаторы атрибутов следуют после закрывающей фигурной скобки, они считаются относящимися к определённому типу структуры, объединения или перечисления, а не к охватывающему объявлению, в котором встречается спецификатор типа; определённый тип становится полным только после спецификаторов атрибутов.

Все остальные атрибуты

В остальных случаях спецификатор атрибута входит в состав объявления, включая объявления безымянных параметров и имён типов, и относится к этому объявлению (которое может быть вложено в другое объявление, например в случае объявления параметра) либо к конкретному деклараторам внутри объявления. Если спецификатор атрибута применяется к параметру, объявленному как функция или массив, он должен применяться к функции или массиву, а не к указателю, в который параметр неявно преобразуется, однако эта возможность пока реализована неверно.

Любой список спецификаторов и квалификаторов в начале объявления может содержать спецификаторы атрибутов независимо от того, допускаются ли в таком списке в данном контексте спецификаторы класса хранения. (Однако некоторые атрибуты по сути подобны спецификаторам класса хранения и имеют смысл только там, где допустимы спецификаторы класса хранения; например, section.) У этого синтаксиса есть одно необходимое ограничение: первое объявление параметра в старом стиле в определении функции не может начинаться со спецификатора атрибута, поскольку в соответствии с описанным ниже синтаксисом такой атрибут относится к самой функции (однако в этом случае такой синтаксис ещё не реализован). В некоторых других случаях грамматика допускает спецификаторы атрибутов, но компилятор пока их не поддерживает. Все спецификаторы атрибутов в этом месте относятся к объявлению в целом. В устаревающем варианте использования, где тип int подразумевается при отсутствии спецификаторов типа, такой список спецификаторов и квалификаторов может содержать только список спецификаторов атрибутов, без других спецификаторов или квалификаторов.

В настоящее время первый параметр в прототипе функции должен иметь хотя бы один спецификатор типа, не являющийся спецификатором атрибута; это устраняет неоднозначность при интерпретации void f(int (__attribute__((foo)) x)), однако данное правило может измениться. В настоящее время, если круглые скобки декларатора функции содержат только атрибуты, эти атрибуты игнорируются, а не приводят к ошибке или предупреждению и не подразумевают единственный параметр типа int, однако это поведение может измениться.

Список спецификаторов атрибутов может располагаться непосредственно перед декларатором (кроме первого) в разделённом запятыми списке деклараторов объявления нескольких идентификаторов с использованием одного списка спецификаторов и квалификаторов. Такие спецификаторы атрибутов применяются только к идентификатору, перед декларатором которого они стоят. Например, в

__attribute__((noreturn)) void d0 (void),
    __attribute__((format(printf, 1, 2))) d1 (const char *, ...),
     d2 (void);

атрибут noreturn применяется ко всем объявленным функциям, а атрибут format — только к d1.

Список спецификаторов атрибутов может располагаться непосредственно перед запятой, «=» или точкой с запятой, завершающей объявление идентификатора, отличное от определения функции. Такие спецификаторы атрибутов применяются к объявленному объекту или функции. Если указано ассемблерное имя объекта или функции (см. раздел Управление именами, используемыми в ассемблерном коде), атрибут должен следовать за спецификацией asm.

В будущем список спецификаторов атрибутов может быть разрешён после декларатора в определении функции (перед объявлениями параметров в старом стиле или телом функции).

В конструкции C99, в которой квалификаторы применяются к указателю, в который массив неявно преобразуется, спецификаторы атрибутов можно смешивать с квалификаторами типа внутри [] декларатора параметра-массива. Такие спецификаторы атрибутов применяются к указателю, а не к массиву, однако в настоящее время эта возможность не реализована, и они игнорируются.

Список спецификаторов атрибутов может располагаться в начале вложенного декларатора. В настоящее время при таком использовании есть некоторые ограничения: атрибуты правильно относятся к декларатору, но для большинства отдельных атрибутов подразумеваемая этим семантика не реализована. Если спецификаторы атрибутов следуют за * декларатора указателя, их можно смешивать с любыми имеющимися квалификаторами типа. Далее описывается формальная семантика этого синтаксиса. Это описание будет наиболее понятно тем, кто знаком с формальной спецификацией декларатора в стандарте ISO C.

Рассмотрим (как в C99, пункт 4 подраздела 6.7.5) объявление T D1, где T содержит спецификаторы объявления, задающие тип Type (например, int), а D1 — декларатор, содержащий идентификатор ident. Тип, задаваемый для ident производными деклараторами, тип которых не включает спецификатор атрибута, определяется так же, как в стандарте ISO C.

Если D1 имеет форму ( attribute-specifier-list D ), а объявление T D задаёт для ident тип «derived-declarator-type-list Type», то T D1 задаёт для ident тип «derived-declarator-type-list attribute-specifier-list Type».

Если D1 имеет форму * type-qualifier-and-attribute-specifier-list D, а объявление T D задаёт для ident тип «derived-declarator-type-list Type», то T D1 задаёт для ident тип «derived-declarator-type-list type-qualifier-and-attribute-specifier-list указатель на Type».

Например,

void (__attribute__((noreturn)) ****f) (void);

задаёт тип «указатель на указатель на указатель на указатель на функцию без возвращаемого значения, возвращающую void». Другой пример:

char *__attribute__((aligned(8))) *f;

задаёт тип «указатель на указатель с выравниванием по 8 байтам на char». Обратите внимание, что это не работает для большинства атрибутов; например, использование приведённых выше атрибутов «aligned» и «noreturn» пока не поддерживается.

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

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

Spec-Zone.ru

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