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. См. ниже. 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 foo { int i1; int i2; __u64 x; } __attribute__((aligned(8)));подавляет предупреждение. Компилятор также выводит предупреждение, например, «предупреждение: смещение 'x' 12 в 'struct foo' не выровнено по 8», когда поле структуры имеет невыровненное смещение:
struct foo { int i1; int i2; int i3; __u64 x; } __attribute__((aligned(8)));Это предупреждение можно отключить с помощью -Wno-if-not-aligned.
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, разыменовывающее такой указатель, обрабатывается как имеющее тип 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 или выше. 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++, атрибут видимости (см. Атрибуты функций) также может применяться к типам классов, структур, объединений и перечислений. В отличие от других атрибутов типов, атрибут должен стоять между ключевым словом и именем типа; он не может стоять после тела типа.
Обратите внимание, что видимость типа применяется к сущностям с неявной связью, связанными с классом (vtable, узел typeinfo и т. д.). В частности, если класс выбрасывается как исключение в одном объекте общего использования и перехватывается в другом, класс должен иметь стандартную видимость. В противном случае два объекта общего использования не смогут использовать один и тот же узел typeinfo, и обработка исключений будет нарушена.
Для указания нескольких атрибутов разделяйте их запятыми в двойных скобках: например, ‘__attribute__ ((aligned (16), packed))’.
Далее: Атрибуты типов ARC, Наверх: Атрибуты типов [Оглавление][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-8.5.0/gcc/Common-Type-Attributes.html