Вы можете использовать атрибуты, чтобы указать специальные свойства переменных, параметров функций, или свойства структур, объединений (union), и в случае C++ для полей класса. Некоторые атрибуты в настоящий момент определены главным образом для переменных. Другие атрибуты определены для переменных на частных целевых системах. Некоторые атрибуты доступны для функций (см. Declaring Attributes of Functions [2]), меток (см. Label Attributes [3]), перечислений (см. Enumerator Attributes [4]), операторов (см. Statement Attributes [5]), и для типов (см. Specifying Attributes of Types [6]). Другие фронтэнды (системы разработки) могут определять свои атрибуты (см. описание расширений для языка C++ [7]).
GCC предоставляет два разных способа указания атрибутов: традиционный синтаксис аннотаций __attribute__ ((...)), и более новый стандартный синтаксис C и C++ с использованием [[...]] и префикса gnu:: на именах атрибутов. Обратите внимание, что точные правила размещения атрибутов в исходном коде отличаются в зависимости от используемого вами синтаксиса (см. [8]).
Следующие атрибуты поддерживаются на большинстве целевых систем.
alias ("target")
Атрибут переменной alias приводит к тому, что декларация выпускается как псевдоним (alias) для другого символа, известного как цель псевдонима (alias target). За исключением квалификаторов верхнего уровня alias target должен иметь тот же тип, что и alias. Например, следующий код даст ошибку, если alias target не был определен в той же единице трансляции, что и alias (здесь var_alias определена как псевдоним для целевой переменной var_target):
int var_target;externint __attribute__ ((alias ("var_target"))) var_alias;
Обратите внимание, что при отсутствии атрибута GCC предполагает, что различные объявления с внешней связью (external linkage) обозначают различные объекты. Использование как alias, так и alias target для доступа к одному и тому же объекту не определенно в единице трансляции без объявления с атрибутом alias.
Этот атрибут требует поддержки ассемблера и объектного файла, и может быть недоступен на всех целях компиляции.
Атрибут переменной alloc_size может быть применен к декларации указателя на функцию, которая возвращает указатель, и принимает как минимум один аргумент целочисленного типа. Он показывает, что возвращенный указатель указывает на объект, размер которого задается аргументом функции в позиции position, или произведением аргументов position-1 и position-2. Значимые размеры это положительные значения, которые меньше PTRDIFF_MAX. Другие размеры диагностируются при обнаружении. GCC использует эту информацию для улучшения результатов __builtin_object_size.
Например, следующие декларации указывают, что calloc_ptr это указатель функции, которая, как стандартная функция calloc языка C, возвратит объект, размер которого занят произведением аргументов 1 и 2, и аналогично malloc_ptr, как и стандартная функция malloc языка C, возвратит объект, размер которого указан аргументом 1 функции.
Атрибут copy применяет набор атрибутов, установленных для переменной variable, для другой переменной, к которой применен атрибут copy. Атрибут предназначен для библиотек, определяющих псевдонимы, которые, как ожидается, будут определять тот же набор атрибутов, что и псевдонимные символы. Атрибут copy может использоваться с переменными, функциями или типами. Однако тип символа, к которому применяется атрибут (либо переменная, либо функция), должен соответствовать типу символа, на который ссылается аргумент. Атрибут copy копирует только синтаксические и семантические атрибуты, но не атрибуты, которые влияют на линковку или видимость символа, такие как alias, visibility или weak. Атрибут deprecated также не копируется. См. [10, 11].
deprecated deprecated (msg) mode (mode)
См. далее описание этих атрибутов.
no_icf
Этот атрибут переменной предотвращает её слияния с другой эквивалентной переменной.
noinit
Любые данные переменной с этим атрибутом не будут инициализированы в C runtime startup code или программой загрузчика. Не инициализированные данные это способ уменьшить время старта программы.
Этот атрибут специфичен для целей ELF и полагается на скрипт линкера, чтобы поместить секции с префиксом .noinit prefix в правильную область памяти.
nonstring
Атрибут переменной nonstring указывает, что объект или член декларации с типом массив char, signed char, unsigned char, или указатель на такой тип, предназначен для хранения массива символов, который необязательно должен иметь в конце строки завершающий NUL. Это полезно в детектировании таких массивов или указателей в функциях, которые ожидают NUL-terminated строк, и позволяет избежать предупреждений, когда такой массив или указатель используется как аргумент для связанной функции, манипулирующей строками, такой как strncpy.
Например, без этого атрибута GCC выдаст предупреждение для вызова strncpy, показанного ниже, потому что это может обрезать копирование без добавления завершающего символа NUL. Использование атрибута позволяет подавить это предупреждение. Однако, когда массив декларирован с атрибутом, вызов strlen диагностируется, потому что когда массив не содержит NUL-terminated строку, вызов не определен. Для копирования, сравнения или поиска в не строковых массивах символов используйте memcpy, memcmp, memchr и другие функции, которые работают с массивами байтов. В дополнение, вызов strnlen и strndup с такими массивами безопасен при условии, что подходящее ограничение определено, но не диагностировано.
struct Data {char name [32] __attribute__ ((nonstring)); }; int f (struct Data *pd,constchar*s) {strncpy(pd->name, s,sizeof pd->name);
...
returnstrlen(pd->name);// небезопасно, будет выведено предупреждение }
objc_nullability (вид nullability) (только для Objective-C и Objective-C++)
Этот атрибут применим только к указателям на переменные. Он позволяет пометить указатель одним из 4 возможных значений, описывающих условия с которыми указатель может иметь значение nil. В большинстве случаев этот атрибут предназначен для внутреннего представления свойства и метода, как он может работать с null (nullability, указывается ключевыми словами языка); он не предназначен для прямого использования.
Когда вид nullability "unspecified" или 0, ничего не известно про условия, в которых указатель может быть nil. Конкретизация этого состояния позволяет избежать ложных срабатываний при диагностике.
Когда вид nullability "nonnull" или 1, указатель не имеет значения, если он равен nil, таким образом компилятор свободен для выдачи диагностики, если можно определить, что значение указателя будет равно nil.
Когда вид nullability "nullable" или 2, указатель может быть nil, и это имеет определенный смысл.
Когда вид nullability "resettable" или 3 (используется только в контексте списков атрибутов свойств), это описывает случай, в котором установщик свойства (setter) может принимать значение nil (что возможно приводит к тому, что свойство каким-то образом сбрасывается в значение по умолчанию), но для которого извлекатель свойства (getter) никогда не вернет на законных основаниях nil.
packed
См. далее описание этого атрибута.
persistent
Любые данные с атрибутом persistent не инициализируются C runtime startup code, однако будут инициализированы программой загрузчика. Это позволяет значению переменной сохранять свое состояние (‘persist’) между сбросами процессора.
Этот атрибут специфичен для целей ELF и полагается на скрипт линкера, чтобы поместить секции с префиксом .persistent в правильное место памяти. Особенно это требуется для энергонезависимой (non-volatile), записываемой памяти.
section ("section-name")
См. далее описание этого атрибута.
strict_flex_array (level)
Атрибут strict_flex_array должен быть присоединен к завершающему полю массива структуры. Он управляет тем, когда рассматривать поле конечного массива структуры как гибкий элемент массива для целей доступа к элементам такого массива. Аргумент level должен быть целым числом в диапазоне от 0 до 3.
level=0 это наименее строгий уровень, все завершающие массивы структуры обрабатываются как гибкие элементы массива.
level=3 это самый строгий уровень, только если конечный массив декларирован как гибкий элемент массива в соответствии со стандартом C99 ('[]'), он рассматривается как гибкий элемент массива.
Уровни между 0 и 3 предоставлены для более старых кодов, когда GCC использует zero-length array extension ('[0]') или одноэлементный массив в качестве гибких элементов массива ('[1]'). Когда level=1, завершающий массив обрабатывается как гибкий элемент массива, когда он декларирован либо как '[]', либо как '[0]', или как '[1]'; когда level=2, завершающий массив обрабатывается как гибкий элемент массива, когда он декларирован либо как '[]', либо как '[0]'.
Этот атрибут может быть использован с опцией командной строки -fstrict-flex-arrays, либо без неё. Когда одновременно присутствуют этот атрибут и эта опция, значение level строгости для конкретного завершающего массива определяется атрибутом.
Атрибут strict_flex_array взаимодействует с опцией -Wstrict-flex-arrays. Для дополнительной информации см. "Options to Request or Suppress Warnings" [12].
tls_model ("tls_model")
См. далее описание этого атрибута.
unavailable unavailable (msg)
Атрибут unavailable показывает, что переменная помечена как недоступная, если она используется где-нибудь в исходном файле. Поведение компилятора такое же, как и с атрибутом deprecated, за исключением того, что компилятор выдает ошибку вместо исключения.
Ожидается, что элементы, помеченные как deprecated, будут в конечном итоге удалены из интерфейсов, и затем станут unavailable. Этот атрибут позволяет пометить объект соответствующим образом.
Атрибут unavailable может также использоваться для функций и типов (см. [10, 11]).
unused
Этот атрибут, подсоединенный к переменной или полю структуры, показывает, что переменная или поле подразумеваются возможно не используемыми. GCC не выдает предупреждения для этой переменной или поля.
used
Этот атрибут, подсоединенный к переменной или к статическому хранилищу, показывает, что переменная должна быть выпущена даже если к ней никто не обращается.
Будучи примененным к статическому полю данных шаблона класса C++, этот атрибут также означает, что этот член класса инстанцируется, если инстанцирован сам класс.
retain
Для целей ELF, которые поддерживают GNU или FreeBSD OSABI, этот атрибут сохранит переменную от удаления сборщиком мусора линкера. Чтобы поддерживает это поведение, переменные, которые не помещены в специальные секции (т. е. с помощью атрибута section или опцией -fdata-sections), будут размещены в новых, уникальных секциях.
Эта дополнительная функциональность требует Binutils version 2.36 или более свежих.
uninitialized
Этот атрибут, присоединенный к переменной с automatic хранилищем, будет означать, что эта переменная не должна быть автоматически инициализирована компилятором, когда присутствует опция -ftrivial-auto-var-init.
С опцией -ftrivial-auto-var-init все автоматические переменные, которые не имеют явных инициализаторов, будут инициализированы компилятором. Эти дополнительные инициализации компилятора могут внести дополнительные накладные расходы run-time, которые иногда драматичны. Этот атрибут может использоваться для пометки некоторых переменных для исключения их из автоматической инициализации, чтобы снизить runtime-затраты.
Этот атрибут не дает эффекта, когда не присутствует опция -ftrivial-auto-var-init.
vector_size (bytes)
См. далее описание этого атрибута.
visibility ("visibility_type")
Этот атрибут влияет на linkage декларации, к которой он прикреплен. Он может быть применен к переменным (см. [10]) и типам (см. [11]), а также к функциям.
Поддерживаемые значения для visibility_type: default, hidden, protected или internal visibility.
void __attribute__ ((visibility ("protected"))) f () {/* Какие-то действия. */;} int i __attribute__ ((visibility ("hidden")));
Возможные значения visibility_type соответствуют настройки видимости в ELF gABI.
default. Видимость default это нормальный случай для формата объектного файла. Это значение доступно для атрибута visibility, чтобы переопределить другие опции, которые могут поменять подразумеваемую видимость объектов.
На ELF видимость default означает, что декларация видна для других модулей. И в совместно используемых библиотеках эта видимость означает что декларируемый объект может быть переназначен.
На Darwin видимость default означает, что декларация видима для других модулей.
Видимость default соответствует в языке "external linkage".
hidden. Видимость hidden показывает, что декларируемый объект имеет новую форму linkage, который мы называем "hidden linkage". Две декларации объекта с hidden linkage относятся к одному и тому же объекту, если они находятся в одном и том же общем объекте.
internal. Видимость internal работает наподобие видимости hidden, однако с дополнительной семантикой, специфичной для процессора. Если это не указано иначе через psABI, GCC определяет internal видимость так, что функция никогда не вызывается из другого модуля. Сравните это с функциями hidden, на которые, хотя на них не могут напрямую ссылаться другие модули, есть возможность ссылаться косвенно через указатели на функции. Указанием, что функция не может быть вызвана вне модуля, GCC например может пропустить загрузку регистра PIC, поскольку известно, что вызывающая функция загрузила правильное значение.
protected. Видимость protected работает наподобие видимости default, за исключением того, что указывает на привязку ссылок в определяющем модуле к определению в этом модуле. Т. е. объявленная сущность не может быть переопределена другим модулем.
Все варианты видимостей поддерживаются многими, но не всеми целями ELF targets (поддерживаются, когда ассемблер поддерживает псевдооператор '.visibility'). Видимость default поддерживается везде. Видимость hidden поддерживается целями Darwin.
Атрибут visibility должен применяться только к объявлениям, которые в противном случае имели бы внешнюю связь (external linkage). Атрибут должен применяться последовательно, чтобы одна и та же сущность не объявлялась с различными настройками атрибута.
На C++ атрибут visibility применяется как к типам, так и к функциям и объектам, потому что в C++ типы имеют связь (linkage). У класса не может быть больше видимости, чем его нестатические типы и базы элементов данных, а члены класса по умолчанию имеют видимость своего класса. Кроме того, объявление без явной видимости ограничено видимостью его типа.
На C++ вы можете пометить методы и статические свойства класса атрибутом видимости. Это полезно, если вы знаете, что определенный метод или статическая переменная должна использоваться только из одного общего объекта; тогда вы можете пометить hidden остальную часть класса, у которого видимость default. Необходимо проявлять осторожность, чтобы не нарушить правило единого определения (One Definition Rule); например, обычно бесполезно помечать inline-метод как hidden, не помечая весь класс как hidden.
Декларация C++ namespace также может иметь атрибут visibility.
namespace nspace1 __attribute__ ((visibility ("protected"))) {/* Какие-то действия. */;}
Этот атрибут применим только к конкретному телу пространства имен (namespace), а не к другим определениям того же namespace; это эквивалентно использованию '#pragma GCC visibility' перед и после определения namespace (см. врезку "Видимость #pragma").
На C++, если аргумент шаблона имеет ограниченную видимость, это ограничение неявно распространяется на инстанциацию шаблона. В противном случае для экземпляров и специализаций шаблонов по умолчанию устанавливается видимость шаблона.
Если и шаблон, и класс с вложением имеют явную видимость, используется видимость из шаблона.
warn_if_not_aligned (alignment)
Этот атрибут указывает порог выравнивания для поля структуры, измеряемое в байтах. Если поле структуры получилось выровненным ниже порога, то будет выдано предупреждение. Например, следующая декларация выдаст предупреждение для структуры foo, примерно такое: "warning: alignment 8 of 'struct foo' is less than 16".
struct foo {int i1;int i2;unsignedlonglong x __attribute__ ((warn_if_not_aligned (16))); };
Компилятор также выдаст примерно такое предупреждение "warning: 'x' offset 8 in 'struct foo' isn't aligned to 16", когда поле структуры имеет не выровненное смещение:
#pragma GCC visibility push(visibility) #pragma GCC visibility pop
Эта pragma-директива дает возможность пользователю установить видимость для нескольких деклараций без необходимости каждому определению давать атрибут visibility (см. документацию по декларированию атрибутов для функций [2]).
На C++ директива #pragma GCC visibility влияет только на декларации области действия пространства имен (namespace-scope declarations). Члены класса и специализации шаблона не подвержены влиянию; если вы хотите переназначить visibility для определенного члена инстанцирования, то необходимо использовать атрибут.
Атрибут aux используется для непосредственного доступа к дополнительному пространству регистров блока ARC (ARC’s auxiliary register space) из языка C. Номер auxilirary-регистра указывается в аргументе этого атрибута.
Атрибут progmem используется на платформе AVR для размещения данных, предназначенных только для чтения, (read-only data) в энергонезависимой памяти программ (non-volatile program memory, flash). Атрибут progmem помещает соответствующие объекты в секцию, имя которой начинается на .progmem.
Этот атрибут работает подобно атрибуту section, однако добавляет дополнительную проверку.
• Для обычных ядер AVR с 32 регистрами общего назначения: progmem влияет на место размещения данных, но не на то, как к этим данным происходит обращение. Чтобы прочитать данные, находящиеся в декларации с атрибутом progmem (inline), должны использоваться ассемблер (специальные функции).
/* Использование макроса из AVR-LibC */ #include < avr/pgmspace.h> /* Размещение var в памяти flash */ constint var[2] PROGMEM ={1,2}; int read_var (int i) {/* Доступ к var[] с помощью специального макроса из avr/pgmspace.h */return(int) pgm_read_word (& var[i]); }
Платформа AVR имеет Гарвардскую архитектуру ядра, в которой данные и данные только для чтения обычно находятся в памяти данных (RAM).
См. также секцию описания имен адресных пространств AVR [13] для альтернативного способа обращения к данным в памяти flash.
• Для ядер AVR, у которых память flash доступна в адресном пространстве RAM: на таких устройствах нет никакой необходимости в атрибуте progmem или в использовании квалификатора __flash. Просто используйте стандартный код C/C++, компилятор будет генерировать LD* инструкции. Поскольку память flash видна в адресном пространстве RAM, и файл настроек линкера по умолчанию (default linker script) не помещает .rodata в RAM, не нужен специальный функционал, чтобы тратить RAM для read-only данных, или чтобы читать данные из flash. Вы даже можете получить несколько повышенную производительность, если будете избегать использования progmem и __flash. Это применимо для устройств из семейств avrtiny и avrxmega3, для обзора см. описание опций AVR [14].
• Урезанные ядра AVR Tiny, типа ATtiny40: компилятор добавит 0x4000 к адресам объектов и декларациям в progmem, и разместит объекты в памяти flash, а именно в секции .progmem.data. Это смещение нужно потому, что память flash видима в адресном пространстве, начиная с адреса 0x4000. Благодаря этому к данным в progmem можно получить доступ из обычного кода C, не требуются специальные функции или макросы.
/* Переменная находится в памяти flash */ externconstint var[2] __attribute__((progmem)); int read_var (int i) {return var[i]; }
Имейте в виду, что для таких устройств вообще не нужен атрибут progmem.
io io (addr)
Переменные с атрибутом io используются для адресации отображенных на память периферийных устройств в диапазоне адресов I/O, никакая память не выделяется. Если указан адрес addr, то переменная назначается на этот адрес, и значение интерпретируется как адрес в пространстве данных. Пример:
volatileint porta __attribute__((io (__AVR_SFR_OFFSET__ +0x2)));
Иначе переменной адрес не назначается, однако компилятор все еще будет использовать инструкции in и out там, где это применимо, подразумевая, что другие модули назначили адрес в пространстве адресов I/O. Пример:
externvolatileint porta __attribute__((io));
io_low io_low (addr)
Это работает наподобие атрибута io, но дополнительно информирует компилятор, что этот объект находится в нижней половине области I/O, позволяя использовать инструкции cbi, sbi, sbic и sbis.
address (addr)
Переменные с атрибутом address могут использоваться для периферийных устройств, отображенных на память, которые могут лежать вне диапазона адресов I/O. Точно так же, как и для атрибутов io и io_low, никакая память не выделяется.
volatileint porta __attribute__((address (0x600)));
Этот атрибут также может использоваться для определения символов в коде C/C++, что иначе потребовало бы использование ассемблера, файла настроек линкера (linker description file, LDF), или опций командной строки наподобие -Wl,--defsym,a_symbol=value. Например:
int a_symbol __attribute__((weak, address (1234)));
будет скомпилирован в:
.weak a_symbol
a_symbol = 1234
absdata
Переменные в статическом хранилище и с атрибутом absdata могут быть доступны через инструкции LDS и STS, которые принимают абсолютные адреса.
Этот атрибут поддерживается только для урезанных ядер AVR Tiny, наподобие ATtiny40.
Вы должны гарантировать, что соответствующие данные находятся в адресном пространстве 0x40 .. 0xbf, доступном через инструкции LDS и STS. Единственный способ достичь этого - использовать файл настроек линкера (linker description file, LDF).
Если место размещения не укладывается в диапазон адресов инструкций LDS и STS, то в настоящий момент (Binutils 2.26) будет выдано неопределенное предупреждение наподобие наподобие "module.cc:(.text+0x1c): warning: internal error: out of range error".
В настоящий момент для памяти L1 в архитектуре Blackfin определено 3 атрибута.
l1_data l1_data_A l1_data_B
Используйте эти атрибуты для размещения переменной в L1 Data SRAM. Переменные с атрибутом l1_data помещаются в специальную секцию с именем .l1.data. Переменные с атрибутом l1_data_A помещаются в специальную секцию с именем .l1.data.A. Переменные с атрибутом l1_data_B помещаются в специальную секцию с именем .l1.data.B.
l2
Используйте этот атрибут, чтобы поместить переменную в L2 SRAM. Переменные с атрибутом l2 помещаются в специальную секцию с именем .l2.data.
Эти атрибуты переменной определены для целей H8/300:
eightbit_data
Используйте этот атрибут на H8/300, H8/300H и H8S, чтобы показать, что указанная переменная должна быть помещена в 8-битную секцию данных. Компилятор будет генерировать более эффективный код для определенных операций над данными в этой области. Обратите внимание, что 8-битная область данных (eight-bit data area) ограничена 256 байтами данных.
Чтобы этот атрибут работал корректно, вы должны использовать GAS и GLD из GNU binutils version 2.7 или более свежей версии.
tiny_data
Используйте этот атрибут на H8/300H и H8S, чтобы показать, что указанная переменная должна быть размещена в секции tiny data. Компилятор генерирует более эффективный код для загрузки и сохранения данных в секции tiny data. Имейте в виду, что область tiny data ограничена небольшим пространством 32KB данных.
IA-64 back end поддерживает следующие атрибуты переменной:
model (model-name)
На IA-64 используйте этот атрибут для установки адресуемости объекта. В настоящее время поддерживается только идентификатор small для имени модели (model-name), показывающий адресуемость через "малые" (22-разрядные) адреса (чтобы эти адреса могли быть загружены инструкцией addl). Предостережение: такая адресация по определению не является позиционно независимой, и следовательно этот атрибут не должен использоваться для объектов, определенных общими (shared) библиотеками.
Для архитектуры LoongArch в настоящее время определен один атрибут.
model("name")
Используйте этот атрибут на LoongArch, чтобы применить другую модель кода для адресации этой переменной, отличающуюся от модели, заданной глобальной опцией -mcmodel. Этот атрибут главным образом полезен, если атрибут section и/или файл настроек линкера разместит специальным образом разместит этот объект. В настоящий момент для параметра name поддерживаются njkmrj normal и extreme.
Для M32R/D в настоящий момент определен один атрибут.
model (model-name)
Использование этого атрибута на M32R/D установит адресуемость объекта. Идентификатор model-name это может быть один из вариантов small, medium или large, представляющих модель кода.
Модель small объектов размещаются в младших 16MB памяти (так что их адреса могут быть загружены инструкцией ld24).
Модели объектов medium и large могут находиться в любом месте 32-битного адресного пространства (компилятор будет генерировать инструкции seth/add3 для загрузки их адресов).
Вы можете использовать эти атрибуты на целях Microsoft Windows. На всех целях x86 для дополнительной совместимости Windows доступны x86 Variable Attributes.
Эти атрибуты такие же, как и атрибуты функций MSP430 с таким же именем (см. [15]).
lower
Эта опция работает почти так же, как и атрибут функции MSP430 с таким же именем (см. [15]), но с некоторым дополнительным функционалом.
Если передана опция -mdata-region={upper,either,none}, или к переменной применен атрибут section, то компилятор буде генерировать инструкции 430X. Причина в том, что компилятор подразумевает, что переменная может быть помещена в верхнюю область памяти (выше адреса 0xFFFF). Пометка переменной атрибутом lower информирует компилятор о том, что эта переменная будет помещена в нижнюю память, так что для неё безопасно использовать инструкции 430.
В случае атрибута section будет использоваться имя секции, и префикс .lower не будет добавлен.
Эти атрибуты переменных поддерживаются Nvidia PTX back end:
shared
Используйте этот атрибут, чтобы поместить переменную в адресное пространство .shared памяти. Эта область памяти приватная для каждого кооперативного массива потоков; только потоки в пределах одного блока потока обращаются к одному и тому же экземпляру переменной. Код runtime не инициализирует переменные в этой области памяти.
Для конфигураций PowerPC в настоящее время определены три атрибута: altivec, ms_struct и gcc_struct.
altivec
Атрибут altivec позволяет декларировать векторные типы данных AltiVec, поддерживаемые руководством программирования (AltiVec Programming Interface Manual). Этот атрибут требует аргумента, чтобы указать один из типов вектора: vector__, pixel__ (за которым всегда следует unsigned short) и bool__ (за которым всегда следует unsigned).
RL78 back end поддерживает атрибут переменной saddr. Он задает размещение соответствующей переменной в области SADDR, к которой можно обратиться более эффективно, чем к региону памяти по умолчанию.
Для конфигураций x86 в настоящее время поддерживаются атрибуты ms_struct и gcc_struct.
ms_struct gcc_struct
Если на структуре использовалось packed, или если используются битовые поля, то может получиться, что Microsoft ABI упаковывает их не так, как их обычно упаковывает GCC. В частности, при перемещении упакованных данных между функциями, скомпилированными GCC, и native-компилятором от Microsoft (либо через вызов функции, или как данные в файле), может потребоваться доступ к любому формату.
Атрибуты ms_struct и gcc_struct соответствуют опциям командной строки -mms-bitfields и -mno-ms-bitfields. См. описание опций x86 для подробностей, как они влияют на конфигурацию структуры.
В настоящий момент для конфигураций xstormy16 определен один атрибут: below100.
below100
Если у переменной определен атрибут below100 (разрешен также BELOW100), то GCC поместит переменную в первые 0x100 байт памяти, и для доступа к ней будут использоваться специальные коды операций. Такие переменные будут помещены либо в секцию .bss_below100, либо в секцию .data_below100.
Для конфигураций i386 в настоящий момент определено два атрибута: ms_struct и gcc_struct.
ms_struct gcc_struct
Если на структуре использовалось packed, или если используются битовые поля, то может получиться, что Microsoft ABI упаковывает их не так, как их обычно упаковывает GCC. В частности, при перемещении упакованных данных между функциями, скомпилированными GCC, и native-компилятором от Microsoft (либо через вызов функции, или как данные в файле), может потребоваться доступ к любому формату.
В настоящее время предоставляется -m[no-]ms-bitfields для компиляторов Microsoft Windows X86, чтобы соответствовать native-компилятору Microsoft.
[Указание атрибутов переменных]
Ключевое слово __attribute__ позволяет указать атрибуты переменных или полей структуры. За этим ключевым словом следует спецификация атрибута в двойных скобках. Некоторые атрибуты предназначены для переменных, другие для функций, некоторые атрибуты предназначены для использования в определенных платформах (см. врезки).
Вы также можете указать атрибуты, подставляя двойное подчеркивание '__' перед и после каждого ключевого слова. Это дает возможность использовать их в заголовочных файлах, не беспокоясь о возможном существовании макроса с таким же именем. Например, можно использовать __aligned__ вместо aligned (подробности синтаксиса см. [8]).
aligned aligned (alignment)
Этот атрибут указывает минимальное выравнивание в памяти для переменной или поля структуры, измеряемое в байтах. Например, в следующей декларации дается указание компилятору размещать переменную x по адресу, нацело делящемуся на 16 (16-байтное выравнивание):
int x __attribute__ ((aligned (16)))=0;
На процессорах 68040 это может использоваться в сочетании с выражением asm для доступа инструкции move16, для которой требуются операнды с 16-байтным выравниванием.
Также вы можете указывать выравнивание для полей структуры. Например, чтобы создать пару переменных int, выровненных в памяти на двойное слово, можно написать следующее:
Это альтернатива созданию объединения (union) с двойным членом, который заставляет объединение быть выровненным на двойное слово (8 байт).
В предыдущих примерах было явно указано значение выравнивания в байтах. Альтернативно вы можете опустить коэффициент выравнивания, и просто запросить у компилятора сделать выравнивание переменной или поля структуры для максимального полезного для целевой архитектуры значения выравнивания. Например:
short array[3] __attribute__ ((aligned));
Если в спецификации alignment не указано значение выравнивания, то компилятор автоматически установит выравнивания для декларируемой переменной на наибольшее выравнивание, которое когда-либо использовалось для любого типа данных целевой машины, для которой осуществляется компиляция. Если поступать таким образом, то это потенциально позволяет получить для операций копирования более эффективный в плане скорости выполнения код, потому что компилятор может использовать любые инструкции, копирующие самые большие куски памяти.
Атрибут aligned может только увеличить выравнивание; однако вы также можете уменьшить выравнивание, используя атрибут packed, см. далее.
Обратите внимание, что эффективность атрибутов выравнивания может быть ограничена внутренними особенностями линкера (компоновщика программы). На многих системах линкер может организовать выравнивание только до определенного максимального значения (для некоторых линкеров это максимальное поддерживаемое выравнивание может быть очень маленьким). Если ваш линкер может выравнивать переменные максимум только на 8 байт, то указание aligned(16) в __attribute__ все еще даст выравнивание на 8 байт. Для дополнительной информации см. документацию на используемый линкер.
cleanup (cleanup_function)
Атрибут cleanup запускает функцию, когда переменная выходит за пределы области действия. Этот атрибут может применяться только только к переменным области действия автофункции; он не может быть применен к параметрам или переменным со статическим местом хранения. Функция должна принимать один параметр, указатель на тип, совместимый с переменной. Возвращаемое значение функции (если оно есть) игнорируется.
Если разрешено -fexceptions, то cleanup_function запустится во время разматывания стека, которое происходит при обработке исключения. Обратите внимание что атрибут cleanup не позволяет перехватывать исключение, и только выполняет действие. Не определено, что произойдет, если cleanup_function не выполнит нормальный возврат.
common nocommon
Атрибут common запрашивает GCC поместить переменную в хранилище "common". Атрибут nocommon запрашивает обратное - выделять место напрямую.
Эти атрибуты отменяют выбираемые по умолчанию флаги -fno-common и -fcommon соответственно.
deprecated deprecated (msg)
Атрибут deprecated приводит к предупреждению, если переменная использовалась в любом месте файла исходного кода. Это может быть полезным для идентификации переменных, которые ожидают удаления в будущей версии программы (deprecated переводится как "устарело"). Предупреждение также включает место декларации deprecated-переменной, чтобы упростить поиск дополнительной информации о том, почему переменная устарела, или что нужно сделать вместо неё. Например:
externint old_var __attribute__ ((deprecated)); externint old_var; int new_fn (){return old_var;}
Обратите внимание, что предупреждение произойдет только для использования переменной в строке 3, но не в строке 2.
Атрибут deprecated также может использоваться для функций и типов (см. [2, 6]).
mode (mode)
Этот атрибут задает тип данных для декларации - в зависимости от того, какой тип соответствует режиму mode. По сути это позволяет запрашивать целочисленный тип integer или тип плавающей точки в соответствии с его шириной.
Вы также можете указать режим 'byte' или '__byte__', чтобы показать режим, соответствующий однобайтному целому, 'word' или '__word__' для режима целочисленного слова и 'pointer' или '__pointer__' для режима представления указателей.
packed
Атрибут packed указывает, что переменная или поле структуры занимают самый малый возможный объем памяти с выравниванием на 1 байт для переменной и 1 бит для поля бит, за исключением случаев, когда не указано большее значение выравнивания с помощью атрибута aligned.
В следующей структуре поле x будет упакованным, т. е. оно будет следовать сразу за полем a:
Обычно компилятор помещает генерируемые объекты в секции наподобие data и bss. Однако иногда нужны дополнительные секции, или необходимо определенные переменные разместить в специальные секции. Это может потребоваться, например, для доступа к регистрам специального назначения определенного оборудования (периферийным устройствам MCU). Атрибут section указывает, что переменная (или функция) живет в определенной секции. Например, в следующей маленькой программе используются несколько определенных имен секций:
Используйте атрибут section вместе с инициализируемыми определениями глобальной переменной, как показано в примере выше. GCC выдаст предупреждение, и иначе будет игнорировать атрибут section в декларациях не инициализируемых переменных.
Атрибут section можно использовать только с полностью инициализированным глобальным определением из-за способа работы линковщиков. Линкер требует, чтобы каждый объект был определен однократно, за исключением того, что не инициализированные переменные предварительно переходят в общую секцию common (или bss), и эти переменные могут быть "определены" несколько раз. Вы можете принудительно заставить переменную быть инициализированной с помощью флага -fno-common или атрибута nocommon.
Некоторые форматы файла не поддерживают произвольные секции, поэтому атрибут section не доступен на всех платформах. Если вам необходимо отобразить все содержимое модуля на определенную секцию, то рассмотрите вместо этого функциональные средства линкера.
shared
На Microsoft Windows, в дополнение к размещению определений переменной в именованной секции, секция может также совместно использоваться (shared) между всеми запущенными копиями исполняемого кода или DLL. Например, эта маленькая программа определяет shared данные путем помещения их в именованную секцию shared, и помечает эту секцию как совместно используемую атрибутом shared:
int foo __attribute__((section ("shared"), shared))=0; int main() {/* Чтение и запись foo. Все запущенные копии увидят
одно и то же значение этой переменной. */return0; }
Вы можете использовать атрибут shared вмести с атрибутом section только для инициализированных глобальных определений, потому что этого требует линкер (для дополнительной информации см. выше описание атрибута section).
Атрибут shared доступен только на Microsoft Windows.
tls_model ("tls_model")
Атрибут tls_model устанавливает модель хранения thread-local (см. [9]) определенной переменной __thread, отменяя действие опции командной строки -ftls-model= для переменной, где атрибут применен. Аргументом атрибута tls_model должен быть один из вариантов global-dynamic, local-dynamic, initial-exec или local-exec.
Этот атрибут поддерживают не все целевые платформы.
unused
Этот атрибут, будучи присоединенным к переменной, означает, что переменная возможно не используемая. GCC не будет генерировать предупреждение для этой переменной, если она определена и присвоена, но не используется.
vector_size (bytes)
Этот атрибут задает размер вектора (т. е. массива или области памяти) для переменной, измеряемый в байтах. Например, Например, в следующей декларации компилятор установит режим для переменной foo на 16 байт, поделенный на порции размером в int. Если предположить, что размер int составляет 32 бита (вектор из 4 элементов, каждый по 4 байта), то соответствующий режим foo будет V4SI:
int foo __attribute__ ((vector_size (16)));
Этот атрибут применим только для интегральных и float скаляров, хотя с этой конструкцией разрешены массивы, указатели и возвращаемые значения из функций.
Агрегаты с этим атрибутом недопустимы, даже если у них такой же размер, что и соответствующий скаляр. Например, следующая декларация недопустима, даже если размер структуры такой же, как и размер int:
struct S {int a;}; struct S __attribute__ ((vector_size (16))) foo;
selectany
Атрибут selectany приводит к тому, что инициализированная глобальная переменная имеет семантику однократной связи (link-once). Когда линкер встретит несколько определений переменной, то будет выбрано первое определение, а остальные отбрасываются. Следующее используется компилятором Microsoft, линкеру указывается, чтобы он не предупреждал о размере или различиях содержимого нескольких определений.
Хотя основное использование этого атрибута предназначено для типов POD, атрибут selectany может также применен к глобальным объектам C++, которые инициализированы конструктором. В этом случае static-инициализация и код деструктора для объекта опускается в каждой трансляции, определяющей объект, однако вызов конструктора и деструктора защищен переменной link-once.
Атрибут selectany применим только на целевых платформах Microsoft Windows. Вы можете использовать __declspec (selectany) как синоним __attribute__ ((selectany)) для совместимости с другими компиляторами.
weak
Атрибут weak приводит к тому, что декларация выпускается как weak-символ вместо глобального. Атрибут применяется главным образом в определении библиотечных функций, которые могут быть переопределены в коде пользователя, хотя атрибут может также использоваться для деклараций, не относящихся к функциям. Weak-символы поддерживаются целями ELF, и также для целей a.out, когда используется ассемблер и линкер GNU.
Атрибут weakref помечает декларацию как weak ссылку. Без аргументов он должен сопровождаться атрибутом alias, именующим целевой символ. Необязательно цель может быть задана в качестве аргумента для самого weakref. В любом случае weakref неявно помечает декларацию как weak. Без цели, приведенной в качестве аргумента для weakref или для alias, weakref эквивалентен weak.
Ссылка weak это псевдоним (alias), который сам по себе не требует определения целевого символа. Если на целевой символ есть только weak-ссылки, то он становится не определенным weak символом. Однако если на целевой символ есть прямая ссылка, то такие сильные ссылки преобладают, и для символа требуется определение, необязательно в той же самой единице трансляции (translation unit).
Эффект атрибута эквивалентен перемещению всех ссылок на псевдоним в отдельную единицу трансляции, переименованию псевдонима в символ псевдонима, объявлению его как weak, компиляции двух отдельных единиц трансляции и выполнению над ними перезагружаемой линковки.
dllimport
На целевых системах Microsoft Windows и Symbian OS атрибут dllimport приводит к тому, что компилятор обращается к функции или переменной через глобальный указатель, который устанавливается символом экспорта DLL. Атрибут подразумевает внешнее хранилище. На целевых системах Microsoft Windows имя указателя формируется комбинацией _imp__ и имени функции, или имени переменной.
Вы можете использовать __declspec(dllimport) как синоним __attribute__ ((dllimport)), чтобы обеспечить совместимость с другими компиляторами.
В настоящее время атрибут dllimport игнорируется inline-функциями. Если атрибут применяется к определению символа, то произойдет сообщение об ошибке. Если символ ранее был декларирован как dllimport, определяется позднее, то атрибут игнорируется последующими ссылками, и генерируется предупреждение. Этот атрибут также отменяется последующей декларацией как dllexport.
Когда атрибут dllimport применяется к классам C++, он помечает не inline функции класса и статические данные как импортируемые. Однако этот атрибут игнорируется для виртуальных методов, чтобы разрешить создание vtables с использованием преобразователей (thunks).
На целевых системах SH Symbian OS атрибут dllimport также имеет другой эффект - он может привести к тому, что экспортируется vtable и информация типов времени выполнения (run-time type information) для класса. Это происходит, когда у класса есть конструктор с атрибутом dllimport или не inline методы, non-pure virtual функция и, для любых из этих двух случаев, класс также имеет inline-конструктор или деструктор, и имеет ключевую функцию, которая определена в текущей единице трансляции.
Для целевых систем Microsoft Windows использование атрибута dllimport на функциях необязательно, но дает некоторый прирост производительности благодаря устранению преобразователя (thunk) в DLL. Использование атрибута dllimport на импортируемых переменных ранее требовалось на более старых версиях линкера GNU, однако этого теперь можно избежать передачей линкеру GNU опции --enable-auto-import. Как с функциями, использование атрибута для переменной устраняет thunk в DLL.
Недостаток использования этого атрибута в том, что указатель на функцию или переменную, помеченный как dllimport, не может использоваться как постоянный адрес. На целях Microsoft Windows этот атрибут может быть запрещен для функций установкой флага -mnop-fun-dllimport.
dlexport
На целях Microsoft Windows и Symbian OS атрибут dllexport приводит к тому, что компилятор предоставляет глобальный указатель для указателя в DLL, так что к нему можно обращаться с атрибутом dllimport. На целях Microsoft Windows имя указателя формируется комбинацией _imp__ и имени функции или переменной.
Вы можете использовать __declspec(dllexport) как синоним для __attribute__ ((dllexport)), чтобы обеспечить совместимость с другими компиляторами.
На системах, которые поддерживают атрибут visibility, этот атрибут также подразумевает видимость по умолчанию ("default" visibility), за исключением случаев, когда явно указан атрибут visibility. Вы должны избегать использования dllexport для "hidden" или "internal" visibility; в будущих версиях GCC может генерироваться ошибка для таких случаев.
В настоящий момент атрибут dllexport игнорируется для inline-функций, за исключением использования флага -fkeep-inline-functions. Этот атрибут также игнорируется для undefined-символов.
Когда атрибут применяется к классам C++, он помечает как экспортируемые не inline методы и статические поля класса. Статические константы, инициализируемые в классе, не помечаются, за исключением случаев, когда они также определены вне класса (out-of-class).
Для целей Microsoft Windows существуют альтернативные методы для включения символов в таблицу экспорта DLL, такие как файл .def с секцией EXPORTS, или с линкером GNU ld, путем использования флага линкера --export-all.
[Ссылки]
1. Specifying Attributes of Variables site:gcc.gnu.org. 2. Declaring Attributes of Functions site:gcc.gnu.org. 3. Label Attributes site:gcc.gnu.org. 4. Enumerator Attributes site:gcc.gnu.org. 5. Statement Attributes site:gcc.gnu.org. 6. Specifying Attributes of Types site:gcc.gnu.org. 7. Extensions to the C++ Language site:gcc.gnu.org. 8. Attribute Syntax site:gcc.gnu.org. 9. Thread-Local Storage site:gcc.gnu.org. 10. Common Function Attributes site:gcc.gnu.org. 11. Common Type Attributes site:gcc.gnu.org. 12. Options to Request or Suppress Warnings site:gcc.gnu.org. 13. AVR Named Address Spaces site:gcc.gnu.org. 14. AVR Options site:gcc.gnu.org. 15. MSP430 Function Attributes site:gcc.gnu.org.