6.33.1 Атрибуты общих типов
Следующие атрибуты типа поддерживаются на большинстве целевых платформ.
aligned (alignment)-
Этот атрибут задаёт минимальное выравнивание (в байтах) для переменных указанного типа. Например, объявления:
struct S { short f[3]; } __attribute__ ((aligned (8))); 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 S { short f[3]; } __attribute__ ((aligned));Когда вы опускаете множитель выравнивания в спецификации атрибута
aligned, компилятор автоматически устанавливает выравнивание типа по наибольшему выравниванию, которое когда-либо использовалось для любого типа данных на целевой машине, для которой компилируется программа. Это часто повышает эффективность операций копирования, так как компилятор может использовать инструкции, копирующие большие блоки памяти, при выполнении копирования в или из переменных, для которых вы выровняли типы таким образом.В примере выше, если размер каждого
shortсоставляет 2 байта, то размер всего типаstruct Sсоставляет 6 байт. Наименьшая степень двойки, которая больше или равна этому значению, — 8, поэтому компилятор устанавливает выравнивание всего типаstruct Sв 8 байт.Обратите внимание, что хотя вы можете попросить компилятор выбрать эффективное по времени выравнивание для данного типа, а затем объявить только отдельные объекты этого типа, способность компилятора выбирать эффективное выравнивание полезна в основном только при планировании создания массивов переменных с соответствующим (эффективным выравниванием) типом. Если вы объявляете или используете массивы переменных с эффективно выровненным типом, то, вероятно, ваша программа также выполняет арифметику указателей (или индексирование, что равносильно) с указателями на соответствующий тип, и генерируемый компилятором код для этих операций с указателями часто более эффективен для эффективно выровненных типов, чем для других типов.
Обратите внимание, что эффективность атрибутов
alignedможет быть ограничена внутренними ограничениями вашего линкера. На многих системах линкер может только выровнять переменные до определённого максимального выравнивания. (Для некоторых линков максимальное поддерживаемое выравнивание может быть очень маленьким.) Если ваш линкер может только выровнять переменные до максимального выравнивания 8 байт, то указаниеaligned(16)в атрибуте__attribute__по-прежнему обеспечивает только 8-байтовое выравнивание. Для получения дополнительной информации см. документацию вашего линкера.Атрибут
alignedможет только увеличить выравнивание. Выравнивание может быть уменьшено, указав атрибутpacked. См. ниже. bnd_variable_size-
Когда он применяется к полю структуры, этот атрибут сообщает инструменту проверки границ указателей, что размер этого поля не должен вычисляться с использованием статической информации о типе. Он может использоваться для маркировки полей статических массивов с переменным размером, размещённых в конце структуры.
struct S { int size; char data[1]; } S *p = (S *)malloc (sizeof(S) + 100); p->data[10] = 0; //Bounds violationИспользуя атрибут для поля, мы можем избежать нежелательных проверок нарушений границ:
struct S { int size; char data[1] __attribute__((bnd_variable_size)); } S *p = (S *)malloc (sizeof(S) + 100); p->data[10] = 0; //OK 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, который должен быть строкой, печатается в предупреждении, если он присутствует.
Атрибут
deprecatedтакже может использоваться для функций и переменных (см. Атрибуты функций, см. Атрибуты переменных.) designated_init-
Этот атрибут может быть применён только к типам структур. Он указывает, что любая инициализация объекта этого типа должна использовать обозначенные инициализаторы, а не позиционные. Цель этого атрибута — позволить программисту указать, что структура может измениться, и что поэтому полагаться на позиционные инициализации приведёт к будущим проблемам.
GCC по умолчанию выводит предупреждения на основе этого атрибута; используйте -Wno-designated-init, чтобы подавить их.
may_alias-
Доступы через указатели к типам с этим атрибутом не подпадают под анализ алиасов на основе типа, а вместо этого предполагается, что они могут иметь алиас с любым другим типом объектов. В контексте пункта 7 раздела 6.5 стандарта 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 или выше. packed-
Этот атрибут, прикреплённый к определению типа
structилиunion, указывает, что каждый член (кроме полей битов нулевой ширины) структуры или объединения размещается для минимизации требуемого объёма памяти. Прикреплённый к определениюenum, он указывает, что должен использоваться наименьший целочисленный тип.Указание атрибута
packedдля типовstructиunionэквивалентно указанию атрибута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, а не дляtypedef, которое не определяет перечисление, структуру или объединение. scalar_storage_order ("endianness")-
Прикреплённый к
unionилиstruct, этот атрибут устанавливает порядок хранения, т. е. порядок байтов, скалярных полей типа, а также полей массива, компонентом которого является скаляр. Поддерживаемые порядки байтов —big-endianиlittle-endian. Атрибут не оказывает никакого влияния на поля, которые сами являютсяunion,structили массивом, компонентом которого являетсяunionилиstruct, и эти поля могут иметь другой порядок хранения скаляров, чем в enclosing type.Этот атрибут поддерживается только для целевых платформ, использующих единый порядок хранения скаляров по умолчанию (к счастью, большинство из них), то есть целевых платформ, которые хранят скаляры либо все в 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 не выдает предупреждение для каких-либо переменных этого типа, даже если переменная, кажется, ничего не делает. Это часто происходит с классами блокировки или потоков, которые обычно определяются, а затем не используются, но содержат конструкторы и деструкторы, имеющие функции учёта, которые не тривиальны. visibility-
В C++, атрибут видимости (см. Атрибуты функций) также может применяться к типам классов, структур, объединений и перечислений. В отличие от других атрибутов типа, атрибут должен появляться между исходным ключевым словом и именем типа; он не может появляться после тела типа.
Обратите внимание, что видимость типа применяется к общим ссылкам, связанным с классом (vtable, узел typeinfo и т. д.). В частности, если класс брошен как исключение в одном объекте совместного использования и перехвачен в другом, класс должен иметь видимость по умолчанию. В противном случае два объекта совместного использования не смогут использовать один и тот же узел typeinfo, и обработка исключений будет нарушена.
Для указания нескольких атрибутов разделяйте их запятыми в двойных скобках: например, ‘__attribute__ ((aligned (16), packed))’.
Далее: Атрибуты типов ARM, Наверх: Атрибуты типов [Содержание][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-7.5.0/gcc/Common-Type-Attributes.html