6.35.1 Общие атрибуты типов ¶
Следующие атрибуты типов поддерживаются на большинстве целевых платформ.
-
aligned¶ aligned (alignment)-
Атрибут
alignedуказывает минимальное выравнивание (в байтах) для переменных указанного типа. При указании alignment должен быть степенью двойки. Если alignment не указан, подразумевается максимальное выравнивание для целевой платформы, которое часто, но не всегда, составляет 8 или 16 байт. Например, объявления:struct __attribute__ ((aligned (8))) S { short f[3]; }; typedef int more_aligned_int __attribute__ ((aligned (8)));принуждают компилятор гарантировать (насколько это возможно), что каждая переменная, тип которой
struct Sилиmore_aligned_int, выделяется и выравнивается по крайней мере на границе 8 байт. На SPARC, выравнивание всех переменных типаstruct Sдо границ в 8 байт позволяет компилятору использовать инструкцииlddиstd(загрузка и сохранение двойного слова) при копировании одной переменной типаstruct Sв другую, тем самым повышая эффективность выполнения программы.Обратите внимание, что выравнивание любого типа
structилиunionсогласно стандарту ISO C должно быть по меньшей мере кратно наименьшему общему кратному выравниваний всех элементов структурыstructилиunion. Это означает, что вы можете эффективно настроить выравнивание типаstructилиunionпутем добавления атрибутаalignedк любому элементу такого типа, но обозначение, показанное в примере выше, является более очевидным, интуитивным и читаемым способом запросить у компилятора настроить выравнивание всего типаstructилиunion.Как и в предыдущем примере, вы можете явно указать желаемое выравнивание (в байтах), которое вы хотите использовать для данного типа
structилиunion. В качестве альтернативы, вы можете опустить фактор выравнивания и просто попросить компилятор выровнять тип до максимального полезного выравнивания для целевой машины, для которой вы компилируете. Например, вы можете написать:struct __attribute__ ((aligned)) S { short f[3]; };Всякий раз, когда вы опускаете фактор выравнивания в спецификации атрибута
aligned, компилятор автоматически устанавливает выравнивание для типа до наибольшего выравнивания, которое используется для любого типа данных на целевой машине, для которой вы компилируете. Это часто повышает эффективность операций копирования, потому что компилятор может использовать инструкции, копирующие большие блоки памяти при выполнении копирования в или из переменных с типами, которые вы выровняли таким образом.В примере выше, если размер каждого
shortсоставляет 2 байта, то размер всего типаstruct Sсоставляет 6 байт. Наименьшая степень двойки, которая больше или равна этому, равна 8, поэтому компилятор устанавливает выравнивание для всего типаstruct Sв 8 байт.Обратите внимание, что хотя вы можете попросить компилятор выбрать эффективное выравнивание для данного типа и затем объявить только отдельные самостоятельные объекты этого типа, способность компилятора выбирать эффективное выравнивание, в первую очередь, полезна только тогда, когда вы планируете создавать массивы переменных с соответствующим (эффективным) типом. Если вы объявляете или используете массивы переменных с эффективным типом, то, скорее всего, ваша программа также выполняет арифметику указателей (или индексирование, что эквивалентно) над указателями на соответствующий тип, и код, который компилятор генерирует для этих операций с указателями, часто более эффективен для эффективно выровненных типов, чем для других типов.
Обратите внимание, что эффективность атрибутов
alignedможет быть ограничена внутренними ограничениями вашего компоновщика. На многих системах компоновщик может только организовать выравнивание переменных до определенного максимального выравнивания. (Для некоторых компоновщиков максимальное поддерживаемое выравнивание может быть очень малым.) Если ваш компоновщик может выравнивать переменные только до максимального выравнивания в 8 байт, то указаниеaligned (16)в атрибуте__attribute__по-прежнему обеспечит только выравнивание в 8 байт. См. документацию вашего компоновщика для получения дополнительной информации.При использовании с структурой или членом структуры, атрибут
alignedможет только увеличить выравнивание; чтобы уменьшить его, необходимо также указать атрибутpacked. При использовании в качестве части typedef, атрибутalignedможет как увеличивать, так и уменьшать выравнивание, а указание атрибутаpackedвызывает предупреждение. -
warn_if_not_aligned (alignment)¶ -
Этот атрибут указывает порог для поля структуры, измеренный в байтах. Если поле структуры выровнено ниже порога, будет выдано предупреждение. Например, объявление:
typedef unsigned long long __u64 __attribute__((aligned (4), warn_if_not_aligned (8))); struct foo { int i1; int i2; __u64 x; };приводит к выводу компилятором предупреждения о
struct foo, например, ‘предупреждение: выравнивание 4 для 'struct foo' меньше 8’. Оно используется для определенияstruct fooтаким образом, чтоstruct fooимеет тот же макет, а поле структурыxимеет то же выравнивание, когда__u64выровнено на 4 или 8 байтах. Выравниваниеstruct fooдо 8 байт:struct __attribute__ ((aligned (8))) foo { int i1; int i2; __u64 x; };отключает предупреждение. Компилятор также выдает предупреждение, например, ‘предупреждение: смещение 'x' в 12 в 'struct foo' не выровнено до 8’, когда поле структуры имеет невыровненное смещение:
struct __attribute__ ((aligned (8))) foo { int i1; int i2; int i3; __u64 x; };Это предупреждение может быть отключено с помощью -Wno-if-not-aligned.
alloc_size (position)alloc_size (position-1, position-2)-
Атрибут
alloc_sizeможет быть применён к определению типа функции, возвращающей указатель и принимающей по крайней мере один аргумент целочисленного типа. Он указывает, что возвращаемый указатель указывает на объект, размер которого задаётся аргументом функции в позиции position-1, или произведением аргументов в позициях position-1 и position-2. Значимые размеры — это положительные значения меньшеPTRDIFF_MAX. Другие размеры распознаются как ошибки. GCC использует эту информацию для улучшения результатов__builtin_object_size.Например, следующие объявления
typedef __attribute__ ((alloc_size (1, 2))) void* calloc_type (size_t, size_t); typedef __attribute__ ((alloc_size (1))) void* malloc_type (size_t);
указывают, что
calloc_type— это тип функции, которая, подобно стандартной C-функцииcalloc, возвращает объект, размер которого задаётся произведением аргументов 1 и 2, и чтоmalloc_type, подобно стандартной C-функцииmalloc, возвращает объект, размер которого задаётся аргументом 1 функции. copycopy (expression)-
Атрибут
copyприменяет набор атрибутов, с которыми тип expression был объявлен, к объявлению типа, к которому применяется атрибут. Атрибут предназначен для библиотек, которые определяют псевдонимы, которые, как ожидается, будут указывать на тот же набор атрибутов, что и алиасируемые символы. Атрибутcopyможет использоваться с типами, переменными или функциями. Однако, тип символа, к которому применяется атрибут (либо переменная, либо функция), должен соответствовать типу символа, к которому относится аргумент. Атрибутcopyкопирует только синтаксические и семантические атрибуты, но не атрибуты, которые влияют на связь или видимость символа, такие какalias,visibility, илиweak. Атрибутdeprecatedтакже не копируется. См. Общие атрибуты функций. См. Общие атрибуты переменных.Например, предположим, что
struct Aниже определено в заголовке сторонней библиотеки с требованием выравниванияNи вызовом предупреждения, когда переменная данного типа не выровнена из-за атрибутаpacked. Указание атрибутаcopyв определении несвязанногоstruct Bкопирует все соответствующие атрибуты из типа, на который ссылается выражение указателя, вstruct B.struct __attribute__ ((aligned (N), warn_if_not_aligned (N))) A { /* … */ }; struct __attribute__ ((copy ( (struct A *)0)) B { /* … */ }; deprecateddeprecated (msg)-
Атрибут
deprecatedприводит к предупреждению, если тип используется где-либо в исходном файле. Это полезно для идентификации типов, которые, как ожидается, будут удалены в будущей версии программы. Если это возможно, предупреждение также включает местоположение объявления устаревшего типа, чтобы пользователи могли легко найти дополнительную информацию о том, почему тип устарел, или что им следует сделать вместо этого. Обратите внимание, что предупреждения появляются только для использования, и только если тип применяется к идентификатору, который сам по себе не объявлен устаревшим.typedef int T1 __attribute__ ((deprecated)); T1 x; typedef T1 T2; T2 y; typedef T1 T3 __attribute__ ((deprecated)); T3 z __attribute__ ((deprecated));
приводит к предупреждению на строках 2 и 3, но не на строках 4, 5 или 6. Предупреждение не выдаётся для строки 4, потому что T2 не явно устарел. Строка 5 не вызывает предупреждения, потому что T3 явно устарел. Аналогично для строки 6. Необязательный аргумент msg, который должен быть строкой, выводится в предупреждении, если он присутствует. Управляющие символы в строке будут заменены последовательностями escape, а если опция -fmessage-length установлена в 0 (по умолчанию), любые символы новой строки будут проигнорированы.
Атрибут
deprecatedтакже может быть применен к функциям и переменным (см. Объявление атрибутов функций, см. Указание атрибутов переменных).Сообщение, прикрепленное к атрибуту, зависит от значения опции -fmessage-length.
designated_init-
Этот атрибут может быть применен только к типам структур. Он указывает, что любая инициализация объекта этого типа должна использовать инициализаторы с обозначением, а не позиционные инициализаторы. Цель этого атрибута заключается в том, чтобы позволить программисту указать, что макет структуры может измениться, и что поэтому полагаться на позиционные инициализаторы приведёт к будущим проблемам.
GCC по умолчанию выводит предупреждения, основанные на этом атрибуте; используйте -Wno-designated-init, чтобы их отключить.
may_alias
-
Доступ через указатели на типы с этим атрибутом не подчиняется анализу алиасов на основе типов, а вместо этого предполагается, что они могут быть алиасами любого другого типа объектов. В контексте раздела 6.5, пункт 7 стандарта C99, выражение lvalue, разыменовывающее такой указатель, обрабатывается так, как будто имеет тип char. См. -fstrict-aliasing для получения дополнительной информации о проблемах алиасинга. Это расширение существует для поддержки некоторых векторных API, в которых указатели на один тип вектора могут быть алиасами указателей на другой тип вектора.
Обратите внимание, что объект типа с этим атрибутом не имеет никакой специальной семантики.
Пример использования:
typedef short __attribute__ ((__may_alias__)) short_a; int main (void) { int a = 0x12345678; short_a *b = (short_a *) &a; b[1] = 0; if (a == 0x12345678) abort(); exit(0); }Если вы заменили
short_aнаshortв объявлении переменной, вышеприведённая программа аварийно завершится при компиляции с -fstrict-aliasing, что включено по умолчанию в -O2 и выше. mode (mode)-
Этот атрибут определяет тип данных для объявления — любой тип, соответствующий режиму mode. Это позволяет, по сути, запросить целочисленный или тип с плавающей точкой в соответствии с его шириной.
См. Режим машины в документации GNU Compiler Collection (GCC) Internals для списка возможных ключевых слов для mode. Вы также можете указать режим
byteили__byte__для указания режима, соответствующего целому числу в один байт,wordили__word__для режима целого числа в один слово, иpointerили__pointer__для режима, используемого для представления указателей. packed-
Этот атрибут, прикреплённый к
struct,union, или C++classопределению типа, указывает, что каждый его член (кроме полей битовых полей нулевой ширины) размещается таким образом, чтобы минимизировать занимаемую память. Это эквивалентно указанию атрибутаpackedдля каждого из членов.При прикреплении к определению
enum, атрибутpackedуказывает, что должен использоваться наименьший целочисленный тип. Указание флага -fshort-enums в командной строке эквивалентно указанию атрибутаpackedдля всехenumопределений.В следующем примере члены
struct my_packed_structупакованы плотно, но внутренняя структура его членаsне упакована — для этогоstruct my_unpacked_structтакже должен быть упакован.struct my_unpacked_struct { char c; int i; }; struct __attribute__ ((__packed__)) my_packed_struct { char c; int i; struct my_unpacked_struct s; };Вы можете указать атрибут
packedтолько для определенияenum,struct,union, илиclass, а не дляtypedef, который также не определяет перечисление, структуру, объединение или класс. scalar_storage_order ("endianness")-
При прикреплении к
unionилиstruct, этот атрибут устанавливает порядок хранения, т. е. порядок байтов, скалярных полей типа, а также массивов полей, компонентом которых является скаляр. Поддерживаемые порядки байтов —big-endianиlittle-endian. Атрибут не влияет на поля, которые сами являютсяunion,structили массивами, компонентом которых являетсяunionилиstruct, и возможно, что у этих полей порядок хранения скаляров отличается от порядка хранения скаляров в enclosing типе.Этот атрибут поддерживается только для целей, которые используют единый порядок хранения скаляров по умолчанию (к счастью, большинство из них), т. е. для целей, которые хранят скаляры либо все в формате big-endian, либо все в формате little-endian.
Для типов с обратным порядком хранения скаляров относительно порядка хранения скаляров целевой платформы применяются дополнительные ограничения:
- Взятие адреса скалярного поля
unionилиstructс обратным порядком хранения скаляров запрещено и приводит к ошибке. - Взятие адреса массива, компонентом которого является скаляр, поля
unionилиstructс обратным порядком хранения скаляров разрешено, но приводит к предупреждению, если не указано -Wno-scalar-storage-order. - Взятие адреса
unionилиstructс обратным порядком хранения скаляров разрешено.
Эти ограничения существуют, потому что атрибут порядка хранения теряется при взятии адреса скаляра или адреса массива со скалярным компонентом, поэтому косвенное хранение по этому адресу обычно не работает. Тем не менее, во втором случае разрешено выполнять копирование блока в массив или из массива.
Кроме того, использование punning типов или алиасинга для переключения порядка хранения не поддерживается; то есть, к одному скалярному объекту нельзя получить доступ через различные типы, которые присваивают ему разные порядки хранения.
- Взятие адреса скалярного поля
transparent_union-
Этот атрибут, прикреплённый к
unionопределению типа, указывает, что любой параметр функции, имеющий этот тип объединения, заставляет вызовы этой функции обрабатываться особым образом.Во-первых, аргумент, соответствующий прозрачному типу объединения, может быть любого типа в объединении; никакой приведение типов не требуется. Кроме того, если объединение содержит тип указателя, соответствующий аргумент может быть константой нулевого указателя или выражением указателя типа void; а если объединение содержит тип указателя void, соответствующий аргумент может быть любым выражением указателя. Если тип члена объединения — указатель, квалификаторы, такие как
const, на сославшимся типе должны соблюдаться, так же как и при обычных преобразованиях указателей.Во-вторых, аргумент передаётся в функцию, используя соглашения о вызовах первого члена прозрачного объединения, а не соглашения о вызовах самого объединения. Все члены объединения должны иметь одинаковое представление в памяти; это необходимо для правильной работы передачи аргументов.
Прозрачные объединения предназначены для функций библиотек, которые имеют несколько интерфейсов по причинам совместимости. Например, предположим, что функция
waitдолжна принимать значение либо типаint *для соответствия POSIX, либо значение типаunion wait *для соответствия интерфейсу 4.1BSD. Если параметрwaitбылvoid *,waitпринял бы оба вида аргументов, но он также принял бы любой другой тип указателя, и это сделало бы проверку типа аргумента менее полезной. Вместо этого<sys/wait.h>мог бы определить интерфейс следующим образом:typedef union __attribute__ ((__transparent_union__)) { int *__ip; union wait *__up; } wait_status_ptr_t; pid_t wait (wait_status_ptr_t);Этот интерфейс позволяет передавать аргументы либо
int *, либоunion wait *, используя соглашения о вызовеint *. Программа может вызватьwaitс аргументами любого из этих типов:int w1 () { int w; return wait (&w); } int w2 () { union wait w; return wait (&w); }С этим интерфейсом реализация
waitмогла бы выглядеть так:pid_t wait (wait_status_ptr_t p) { return waitpid (-1, p.__ip, 0); } unused-
При прикреплении к типу (включая
unionилиstruct) этот атрибут означает, что переменные этого типа могут быть потенциально неиспользуемыми. GCC не выводит предупреждение для любых переменных этого типа, даже если переменная, кажется, ничего не делает. Это часто бывает с классами блокировки или потоков, которые обычно определяются, а затем не ссылаются на них, но содержат конструкторы и деструкторы, имеющие нетривиальные функции учёта. vector_size (bytes)-
Этот атрибут указывает размер вектора для типа, измеряемый в байтах. Тип, к которому он применяется, известен как базовый тип. Аргумент bytes должен быть положительной степенью двойки, кратной размеру базового типа. Например, следующие объявления:
typedef __attribute__ ((vector_size (32))) int int_vec32_t ; typedef __attribute__ ((vector_size (32))) int* int_vec32_ptr_t; typedef __attribute__ ((vector_size (32))) int int_vec32_arr3_t[3];
определяют
int_vec32_tкак 32-байтовый векторный тип, состоящий из единиц размеромint. При размереintв 4 байта тип определяет вектор из восьми единиц, по четыре байта каждая. Режим переменных типаint_vec32_t—V8SI.int_vec32_ptr_tопределяется как указатель на такой векторный тип, аint_vec32_arr3_t— как массив из трёх таких векторов. См. Использование векторных инструкций через встроенные функции для получения подробной информации о манипулировании объектами векторных типов.Этот атрибут применим только к целочисленным и с плавающей точкой скалярным типам. В объявлениях функций атрибут применяется к типу возвращаемого значением функции.
Например, следующее:
__attribute__ ((vector_size (16))) float get_flt_vec16 (void);
объявляет
get_flt_vec16как функцию, возвращающую 16-байтовый вектор с базовым типомfloat. visibility-
В C++, атрибут видимости (см. Объявление атрибутов функций) также может быть применён к классам, структурам, объединениям и перечислениям. В отличие от других атрибутов типа, атрибут должен стоять между начальным ключевым словом и именем типа; он не может стоять после тела типа.
Обратите внимание, что видимость типа применяется к неявным связям, связанным с классом (vtable, узел typeinfo и т. д.). В частности, если класс выбрасывается в качестве исключения в одном общем объекте и перехватывается в другом, класс должен иметь видимость по умолчанию. В противном случае два общих объекта не смогут использовать один и тот же узел typeinfo, и обработка исключений будет нарушена.
Для указания нескольких атрибутов разделяйте их запятыми в двойных скобках: например, ‘__attribute__ ((aligned (16), packed))’.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-10.5.0/gcc/Common-Type-Attributes.html