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-
Доступы через указатели к типам с этим атрибутом не подлежат анализу алиасов на основе типов, но вместо этого предполагается, что они могут ссылаться на любые другие типы объектов. В контексте раздела 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 и выше. 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, и возможно, эти поля могут иметь другой порядок хранения скаляров, чем окружающий тип.Этот атрибут поддерживается только для целевых платформ, которые используют единый стандартный порядок хранения скаляров (к счастью, большинство из них), т.е. целевых платформ, которые хранят скаляры либо в формате 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++, атрибут видимости (см. Атрибуты функций) также может быть применён к типам class, struct, union и enum. В отличие от других атрибутов типов, атрибут должен находиться между ключевым словом и именем типа; он не может появляться после тела типа.
Обратите внимание, что видимость типа применяется к неопределённым ссылкам, связанным с классом (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-6.5.0/gcc/Common-Type-Attributes.html