6.37 Указание атрибутов типов
Ключевое слово __attribute__ позволяет указывать специальные атрибуты типов struct и union при определении таких типов. Это ключевое слово следует за указанием атрибута в двойных скобках. В настоящее время определено семь атрибутов для типов: aligned, packed, transparent_union, unused, deprecated, visibility, и may_alias. Другие атрибуты определены для функций (см. Атрибуты функций) и для переменных (см. Атрибуты переменных).
Вы также можете указать любой из этих атрибутов с помощью «__» перед и после его ключевого слова. Это позволяет использовать эти атрибуты в заголовочных файлах, не беспокоясь о возможном макросе с тем же именем. Например, вы можете использовать __aligned__ вместо aligned.
Вы можете указать атрибуты типа в объявлении или определении типа перечисления, структуры или объединения, или для других типов в объявлении typedef.
Для типа перечисления, структуры или объединения вы можете указать атрибуты либо между тегом перечисления, структуры или объединения и именем типа, либо сразу после закрывающей фигурной скобки определения. Предпочтительнее использовать первый синтаксис.
См. Синтаксис атрибутов для получения подробной информации о точном синтаксисе использования атрибутов.
-
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может только увеличить выравнивание; но вы можете уменьшить его, указавpackedтоже. См. ниже.Обратите внимание, что эффективность атрибутов
alignedможет быть ограничена внутренними ограничениями вашего компоновщика. На многих системах компоновщик может только организовать выравнивание переменных до определённого максимального выравнивания. (Для некоторых компоновщиков максимальное поддерживаемое выравнивание может быть очень маленьким.) Если ваш компоновщик может выравнивать переменные только до максимального выравнивания в 8 байт, то указаниеaligned(16)в атрибуте__attribute__всё равно обеспечивает только 8-байтовое выравнивание. Для получения дополнительной информации обратитесь к документации вашего компоновщика. packed- Этот атрибут, присоединённый к определению типа
structилиunion, указывает, что каждый член (кроме полей шириной ноль) структуры или объединения размещается для минимизации требуемого объёма памяти. При присоединении к определениюenum, он указывает, что должен использоваться наименьший целочисленный тип.Указание этого атрибута для типов
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; };Вы можете указать этот атрибут только в определении
enum,structилиunion, а не в определенииtypedef, которое не определяет также перечисление, структуру или объединение. 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 не выводит предупреждение для любых переменных этого типа, даже если переменная, похоже, ничего не делает. Это часто бывает с классами блокировки или потоков, которые обычно определяются, а затем не используются, но содержат конструкторы и деструкторы, которые имеют тривиальные функции учёта. -
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также может использоваться для функций и переменных (см. Атрибуты функций, см. Атрибуты переменных.) 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или более поздних версиях GCC. visibility- В C++, атрибут видимости (см. Атрибуты функций) также может применяться к классам, структурам, объединениям и перечислениям. В отличие от других атрибутов типов, атрибут должен появляться между начальным ключевым словом и именем типа; он не может появляться после тела типа.
Обратите внимание, что видимость типа применяется к неявным ссылкам, связанным с классом (vtable, узел typeinfo и т.д.). В частности, если класс брошен как исключение в одном общем объекте и перехвачен в другом, класс должен иметь видимость по умолчанию. В противном случае два общих объекта не могут использовать один и тот же узел typeinfo, и обработка исключений будет нарушена.
Для задания нескольких атрибутов их нужно разделить запятыми внутри двойных скобок: например, «__attribute__ ((aligned (16), packed))».
6.37.1 Атрибуты типов ARM
На тех целевых платформах ARM, которые поддерживают dllimport (таких как Symbian OS), вы можете использовать атрибут notshared для указания того, что виртуальная таблица и другие подобные данные для класса не должны экспортироваться из DLL. Например:
class __declspec(notshared) C {
public:
__declspec(dllimport) C();
virtual void f();
}
__declspec(dllexport)
C::C() {} В этом коде C::C экспортируется из текущей DLL, но виртуальная таблица для C не экспортируется. (Вы можете использовать __attribute__ вместо __declspec, если предпочитаете, но большинство кода Symbian OS использует __declspec.)
6.37.2 Атрибуты типов MeP
Многие атрибуты переменных MeP могут применяться и к типам. В частности, атрибуты based, tiny, near, и far могут быть применены к обоим. Атрибуты io и cb не могут быть применены к типам.
6.37.3 Атрибуты типов i386
Для конфигураций i386 в настоящее время определены два атрибута: ms_struct и gcc_struct.
-
ms_structgcc_struct - Если
packedиспользуется для структуры или используются битовые поля, то возможно, что Microsoft ABI упаковывает их по-другому, чем GCC. Особенно при перемещении упакованных данных между функциями, скомпилированными с GCC и родным компилятором Microsoft (как через вызов функции, так и как данные в файле), может потребоваться доступ к обоим форматам.В настоящее время
-m[no-]ms-bitfieldsпредоставляется для компиляторов Microsoft Windows X86, чтобы соответствовать родному компилятору Microsoft.
6.37.4 Атрибуты типов PowerPC
Для конфигураций PowerPC в настоящее время определены три атрибута: altivec, ms_struct и gcc_struct.
Для получения полной документации по атрибутам ms_struct и gcc_struct см. документацию в Атрибуты типов i386.
Атрибут altivec позволяет объявлять типы данных векторов AltiVec, поддерживаемые Руководством по программированию AltiVec. Атрибут требует аргумента для указания одного из трех типов векторов: vector__, pixel__ (всегда следует за unsigned short) и bool__ (всегда следует за unsigned).
__attribute__((altivec(vector__))) __attribute__((altivec(pixel__))) unsigned short __attribute__((altivec(bool__))) unsigned
Эти атрибуты в основном предназначены для поддержки ключевых слов __vector, __pixel, и __bool AltiVec.
6.37.5 Атрибуты типов SPU
SPU поддерживает атрибут spu_vector для типов. Этот атрибут позволяет объявлять типы данных векторов, поддерживаемые спецификацией расширений языка Sony/Toshiba/IBM SPU. Он предназначен для поддержки ключевого слова __vector.
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/Type-Attributes.html