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применяет набор атрибутов, с которыми был объявлен тип выражения, к объявлению типа, к которому применен атрибут. Атрибут предназначен для библиотек, которые определяют псевдонимы, которые, как ожидается, определят тот же набор атрибутов, что и алиасированные символы. Атрибут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, который должен быть строкой, печатается в предупреждении, если присутствует. Управляющие символы в строке будут заменены последовательностями экранирования, а если опция -fmessage-length установлена в 0 (ее значение по умолчанию), все символы новой строки будут проигнорированы.
Атрибут
deprecatedтакже может быть использован для функций и переменных (см. Объявление атрибутов функций, см. Указание атрибутов переменных.)Сообщение, прикрепленное к атрибуту, зависит от настройки опции -fmessage-length.
designated_init-
Этот атрибут может быть применен только к структурам типов. Он указывает, что любое инициализирование объекта этого типа должно использовать инициализаторы с указанием места назначения, а не позиционные инициализаторы. Цель этого атрибута — позволить программисту указать, что макет структуры может измениться, и поэтому полагаться на позиционную инициализацию приведет к будущим сбоям.
GCC по умолчанию выводит предупреждения на основе этого атрибута; используйте -Wno-designated-init, чтобы их подавить.
may_alias
-
Доступ к типам с этим атрибутом через указатели не подвержен анализу алиасов на основе типов, а вместо этого предполагается, что они могут создавать алиасы с любым другим типом объектов. В контексте раздела 6.5, пункт 7 стандарта C99, выражение lvalue, разыменовывающее такой указатель, обрабатывается как имеющее тип символа. Для получения дополнительной информации о проблемах с алиасами см. -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. Это фактически позволяет запросить целочисленный или с плавающей точкой тип в соответствии с его шириной.
Список возможных ключевых слов для mode см. в разделе «Режим машины» в «Внутренних сведениях о GNU Компиляторе Коллекции (GCC)» по адресу Machine Modes. Вы также можете указать режим
byteили__byte__для указания режима, соответствующего целому числу с одним байтом,wordили__word__для режима целого числа с одним словом иpointerили__pointer__для режима, используемого для представления указателей. packed-
Этот атрибут, прикрепленный к
struct,union, или определению типа C++, указывает, что каждый его член (кроме полей ширины нуль) размещается для минимизации требуемого объема памяти. Это эквивалентно указанию атрибута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, и эти поля могут иметь другой порядок хранения скаляров, чем окружающий тип.Этот атрибут поддерживается только для целей, которые используют единообразный порядок хранения скаляров по умолчанию (к счастью, большинство из них), т. е. для целей, которые хранят скаляры либо все в формате big-endian, либо все в формате little-endian.
Для типов с обратным порядком хранения скаляров по отношению к порядку хранения скаляров целевой платформы применяются дополнительные ограничения:
- Взятие адреса скалярного поля
unionилиstructс обратным порядком хранения скаляров запрещено и приводит к ошибке. - Взятие адреса поля массива, компоненты которого являются скалярами,
unionилиstructс обратным порядком хранения скаляров разрешено, но приводит к предупреждению, если не указано -Wno-scalar-storage-order. - Взятие адреса
unionилиstructс обратным порядком хранения скаляров разрешено.
Эти ограничения существуют потому, что атрибут порядка хранения теряется при взятии адреса скаляра или массива со скалярным компонентом, поэтому косвенное хранение через этот адрес обычно не работает. Тем не менее, второй случай разрешён для возможности выполнения копирования блока в или из массива.
Кроме того, использование типажнинга или алиасинга для переключения порядка хранения не поддерживается; другими словами, к заданному скалярному объекту нельзя получить доступ через разные типы, которые назначают ему разный порядок хранения.
- Взятие адреса скалярного поля
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, и обработка исключений будет нарушена.
objc_root_class (Objective-C and Objective-C++ only)-
Этот атрибут помечает класс как корневой класс и, таким образом, позволяет компилятору исключить любые предупреждения об отсутствующем суперклассе и выполнять дополнительные проверки необходимых методов по мере необходимости.
Для указания нескольких атрибутов разделяйте их запятыми внутри двойных скобок: например, «__attribute__ ((aligned (16), packed))».
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-11.4.0/gcc/Common-Type-Attributes.html