6.39 Указание атрибутов типов
Ключевое слово __attribute__ позволяет указывать специальные атрибуты типов struct и union при определении таких типов. За этим ключевым словом следует спецификация атрибута в двойных скобках. В настоящее время для типов определено восемь атрибутов: aligned, packed, transparent_union, unused, deprecated, visibility, may_alias и bnd_variable_size. Другие атрибуты определены для функций (см. Атрибуты функций), меток (см. Атрибуты меток) и для переменных (см. Атрибуты переменных).
Вы также можете указать любой из этих атрибутов с помощью ‘__’ перед и после его ключевого слова. Это позволяет использовать эти атрибуты в заголовочных файлах, не беспокоясь о возможном макросе с тем же именем. Например, вы можете использовать __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, де-реферирующее такой указатель, обрабатывается так, как будто имеет тип 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 и выше. visibility-
В C++, атрибут видимости (см. Атрибуты функций) также может быть применён к типам классов, структур, объединений и перечислений. В отличие от других атрибутов типов, атрибут должен располагаться между ключевым словом и именем типа; он не может располагаться после тела типа.
Обратите внимание, что видимость типа применяется к неявным связующим сущностям, связанным с классом (vtable, узел typeinfo и т. д.). В частности, если класс выброшен в виде исключения в одном объекте shared object и перехвачен в другом, класс должен иметь стандартную видимость. В противном случае два shared object не смогут использовать один и тот же узел typeinfo, и обработка исключений будет нарушена.
designated_init-
Этот атрибут может быть применён только к типам структур. Он указывает, что любая инициализация объекта этого типа должна использовать обозначенные инициализаторы, а не позиционные. Целью этого атрибута является указание программисту на то, что расположение структуры может измениться, и что поэтому полагание на позиционные инициализации приведёт к будущим проблемам.
GCC по умолчанию выдаёт предупреждения, основанные на этом атрибуте; используйте -Wno-designated-init для их отключения.
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
Для указания нескольких атрибутов разделяйте их запятыми в двойных скобках: например, ‘__attribute__ ((aligned (16), packed))’.
6.39.1 Атрибуты типов ARM
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.39.2 Атрибуты типов MeP
Многие атрибуты переменных MeP могут быть применены и к типам. В частности, атрибуты based, tiny, near, и far могут быть применены к обоим. Атрибуты io и cb не могут быть применены к типам.
6.39.3 Атрибуты типов PowerPC
В настоящее время для конфигураций PowerPC определены три атрибута: altivec, ms_struct и gcc_struct.
Для получения полной документации по атрибутам ms_struct и gcc_struct обратитесь к документации в разделе Атрибуты типов x86.
Атрибут altivec позволяет объявлять типы данных векторов AltiVec, поддерживаемые руководством по программированию AltiVec. Атрибут требует аргумента для указания одного из трех типов векторов: vector__, pixel__ (всегда за которым следует unsigned short), и bool__ (всегда за которым следует unsigned).
__attribute__((altivec(vector__))) __attribute__((altivec(pixel__))) unsigned short __attribute__((altivec(bool__))) unsigned
Эти атрибуты предназначены в основном для поддержки ключевых слов AltiVec __vector, __pixel, и __bool.
6.39.4 Атрибуты типов SPU
SPU поддерживает атрибут spu_vector для типов. Этот атрибут позволяет объявлять типы векторных данных, поддерживаемые спецификацией расширений языка SPU Sony/Toshiba/IBM. Он предназначен для поддержки ключевого слова __vector.
6.39.5 Атрибуты типов x86
В настоящее время для конфигураций x86 определены два атрибута: ms_struct и gcc_struct.
ms_structgcc_struct-
Если
packedиспользуется для структуры или используются битовые поля, возможно, Microsoft ABI упаковывает их по-другому, чем GCC. Особенно при перемещении упакованных данных между функциями, скомпилированными с GCC и родным компилятором Microsoft (как через вызов функции, так и в виде данных в файле), может потребоваться доступ к одному из форматов.В настоящее время для компиляторов Microsoft Windows x86 предоставляется -m[no-]ms-bitfields для соответствия родному компилятору Microsoft.
Далее: Выравнивание, Предыдущее: Атрибуты переменных, Вверх: Расширения C [Оглавление][Индекс]
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-5.5.0/gcc/Type-Attributes.html