6.4.3.1 Общие атрибуты типов
Следующие атрибуты типов поддерживаются на большинстве целевых платформ.
-
aligned aligned (alignment)-
Атрибут
alignedзадает минимальное выравнивание (в байтах) для переменных указанного типа. Если он задан, аргумент alignment должен быть степенью двойки. Отсутствие аргумента alignment подразумевает максимальное выравнивание для целевой платформы, которое часто, но далеко не всегда, составляет 8 или 16 байт. Например, объявления:struct __attribute__ ((aligned (8))) S { short f[3]; }; typedef int more_aligned_int __attribute__ ((aligned (8)));заставляют компилятор гарантировать (насколько это возможно), что каждая переменная типа
struct Sилиmore_aligned_intбудет размещена и выровнена как минимум по границе 8 байт. На платформе SPARC выравнивание всех переменных типаstruct Sпо границам 8 байт позволяет компилятору использовать инструкцииlddиstd(загрузка и сохранение двойного слова) при копировании одной переменной типаstruct Sв другую, что повышает эффективность выполнения.Обратите внимание, что стандарт ISO C требует, чтобы выравнивание любого заданного типа
structилиunionбыло как минимум точным кратным наименьшему общему кратному выравниваний всех членов рассматриваемой структурыstructили объединенияunion. Это означает, что вы можете эффективно настроить выравнивание типаstructилиunion, прикрепив атрибутalignedк любому из членов такого типа, однако нотация, показанная в примере выше, является более очевидным, интуитивным и читаемым способом запросить у компилятора настройку выравнивания всего типаstructилиunion.Как и в предыдущем примере, вы можете явно указать выравнивание (в байтах), которое компилятор должен использовать для заданного типа
structилиunion. Кроме того, можно опустить коэффициент выравнивания и просто попросить компилятор выровнять тип по максимальному полезному выравниванию для целевой машины, для которой ведется компиляция. Например, вы можете написать:struct __attribute__ ((aligned)) S { short f[3]; };Всякий раз, когда вы опускаете коэффициент выравнивания в спецификации атрибута
aligned, компилятор автоматически устанавливает выравнивание для типа равным наибольшему выравниванию, которое когда-либо используется для любого типа данных на целевой машине, для которой вы компилируете. Это часто делает операции копирования более эффективными, поскольку компилятор может использовать те инструкции, которые копируют самые большие блоки памяти при выполнении копирования в или из переменных с типами, выровненными таким образом.В примере выше, если размер каждого
shortсоставляет 2 байта, то размер всего типаstruct Sравен 6 байтам. Наименьшая степень двойки, которая больше или равна этому значению, равна 8, поэтому компилятор устанавливает выравнивание для всего типаstruct Sравным 8 байтам.Обратите внимание: хотя вы можете попросить компилятор выбрать эффективное по времени выравнивание для заданного типа и затем объявлять только отдельные самостоятельные объекты этого типа, способность компилятора выбирать эффективное по времени выравнивание полезна в первую очередь только тогда, когда вы планируете создавать массивы переменных соответствующего (эффективно выровненного) типа. Если вы объявляете или используете массивы переменных эффективно выровненного типа, то вполне вероятно, что ваша программа также выполняет арифметику указателей (или индексацию, что сводится к тому же самому) для указателей на соответствующий тип, и код, генерируемый компилятором для этих операций арифметики указателей, часто более эффективен для эффективно выровненных типов, чем для других типов.
Обратите внимание, что эффективность атрибутов
alignedможет быть ограничена присущими вашему компоновщику ограничениями. Во многих системах компоновщик способен обеспечить выравнивание переменных только до определенного максимального значения. (Для некоторых компоновщиков максимально поддерживаемое выравнивание может быть очень-очень маленьким.) Если ваш компоновщик способен выравнивать переменные не более чем по 8 байтам, то указаниеaligned (16)в__attribute__все равно обеспечит вам только 8-байтовое выравнивание. Дополнительную информацию см. в документации по вашему компоновщику.При использовании в структуре или члене структуры атрибут
alignedможет только увеличивать выравнивание; для его уменьшения необходимо также указать атрибутpacked. При использовании в составе typedef атрибутalignedможет как увеличивать, так и уменьшать выравнивание, причем указание атрибутаpackedвызывает предупреждение. -
alloc_size (position) alloc_size (position-1, position-2)-
Атрибут типа
alloc_sizeможет применяться к определению типа функции, которая возвращает указатель и принимает по меньшей мере один аргумент целочисленного типа. Он указывает, что возвращаемый указатель указывает на объект, размер которого задается аргументом функции в позиции position-1 или произведением аргументов в позициях position-1 и position-2. Допустимыми размерами являются положительные значения меньшеPTRDIFF_MAX. Другие размеры диагностируются при их обнаружении. GCC использует эту информацию для улучшения результатов__builtin_object_size.Например, следующие объявления
typedef __attribute__ ((alloc_size (1, 2))) void* calloc_type (size_t, size_t); typedef __attribute__ ((alloc_size (1))) void* malloc_type (size_t);
указывают, что
calloc_type— это тип функции, которая, подобно стандартной функции Ccalloc, возвращает объект, размер которого задается произведением аргументов 1 и 2, аmalloc_type, подобно стандартной функции Cmalloc, возвращает объект, размер которого задается аргументом 1 функции. -
copy copy (expression)-
Атрибут
copyприменяет набор атрибутов, с которым был объявлен тип выражения (expression), к объявлению типа, к которому применяется этот атрибут. Атрибут разработан для библиотек, определяющих псевдонимы, которые должны задавать тот же набор атрибутов, что и символы, для которых они являются псевдонимами. Атрибутcopyможет использоваться с типами, переменными или функциями. Тем не менее, тип символа, к которому применяется атрибут (переменная или функция), должен соответствовать типу символа, на который ссылается аргумент. Атрибутcopyкопирует только синтаксические и семантические атрибуты, но не атрибуты, влияющие на компоновку или видимость символа, такие какalias,visibilityилиweak. Атрибутdeprecatedтакже не копируется. См. Общие атрибуты функций. См. Общие атрибуты переменных.Например, предположим, что
struct Aниже определен в каком-то заголовочном файле сторонней библиотеки так, что он имеет требование к выравниваниюNи вызывает предупреждение всякий раз, когда переменная этого типа выровнена ненадлежащим образом из-за атрибутаpacked. Указание атрибутаcopyпри определении независимогоstruct Bприводит к копированию всех релевантных атрибутов из типа, на который ссылается выражение-указатель, вstruct B.struct __attribute__ ((aligned (N), warn_if_not_aligned (N))) A { /* … */ }; struct __attribute__ ((copy ( (struct A *)0)) B { /* … */ }; -
deprecated deprecated (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, который должен быть строкой, выводится в предупреждении, если он присутствует. Управляющие символы в строке будут заменены на escape-последовательности, и если опция -fmessage-length установлена в 0 (ее значение по умолчанию), то любые символы новой строки будут проигнорированы.
Атрибут
deprecatedтакже может использоваться для функций и переменных (см. Объявление атрибутов функций, см. Указание атрибутов переменных).Сообщение, прикрепленное к атрибуту, зависит от настройки опции -fmessage-length.
-
designated_init -
Этот атрибут может применяться только к типам структур. Он указывает, что любая инициализация объекта этого типа должна использовать назначенные инициализаторы (designated initializers), а не позиционные инициализаторы. Цель этого атрибута — позволить программисту указать, что макет структуры может измениться, и поэтому опора на позиционную инициализацию приведет к поломкам в будущем.
GCC по умолчанию выдает предупреждения на основе этого атрибута; используйте -Wno-designated-init, чтобы подавить их.
-
flag_enum -
Этот атрибут может применяться к перечислимому типу, чтобы указать, что его элементы перечисления используются в побитовых операциях, поэтому, например, -Wswitch не должен выдавать предупреждение о
case, соответствующем побитовой комбинации элементов перечисления. -
hardbool hardbool (false_value)hardbool (false_value, true_value)-
Этот атрибут может применяться только к целочисленным типам в C для внедрения защищенных (hardened) булевых типов. Он превращает целочисленный тип в булеподобный тип с тем же размером и точностью, который использует указанные значения в качестве представлений для
falseиtrue. По сути, это на самом деле перечислимый тип, но его наблюдаемое поведение аналогично поведению_Bool, за исключением строгих внутренних представлений, проверяемых во время выполнения.Если true_value опущен, используется побитовое отрицание false_value. Если false_value опущен, используется ноль. Именованные значения представлений должны различаться при преобразовании в исходный целочисленный тип. Более узкие битовые поля отклоняются, если представления становятся неразличимыми.
Значения таких типов автоматически приводятся к
_Bool, после чего выбранные значения представлений сопоставляются с соответствующими значениями_Bool. Если во время компиляции не удается определить, является ли представляемое значение false_value или true_value, проверка во время выполнения вызывает__builtin_trap, если оно не является ни тем, ни другим. Именно это делает их защищенными булевыми типами.При неявном или явном преобразовании скалярных типов в такие защищенные булевы типы поведение соответствует преобразованию в
_Boolс последующим маппингом изfalseиtrueв false_value и true_value соответственно.typedef char __attribute__ ((__hardbool__ (0x5a))) hbool; hbool first = 0; /* False, stored as (char)0x5a. */ hbool second = !first; /* True, stored as ~(char)0x5a. */ static hbool zeroinit; /* False, stored as (char)0x5a. */ auto hbool uninit; /* Undefined, may trap. */
При нулевой инициализации переменной или поля защищенного булева типа (предположительно находящихся в статической памяти) неявный инициализатор нулем преобразуется в
_Bool, а затем в защищенный булев тип, так что начальное значение является защищенным представлением дляfalse. Использование этого значения определено корректно. Это не относится к случаю, когда переменные и поля таких типов не инициализированы (предположительно находятся в автоматической или динамической памяти): их значения неопределенны, и их использование влечет за собой неопределенное поведение (undefined behavior). Их использование может вызывать прерывание (trap) или нет, в зависимости от битов, содержащихся в памяти, (пере)используемой для переменной (если таковая имеется), и от оптимизаций, которые компилятор может выполнить на том основании, что использование неинициализированных значений влечет за собой неопределенное поведение.Пользователи -ftrivial-auto-var-init должны знать, что битовые шаблоны, используемые в качестве инициализаторов, не преобразуются в типы
hardbool, поэтому использование переменнойhardbool, неявно инициализированной с помощью -ftrivial-auto-var-init, может вызвать прерывание, если значения представлений, выбранные дляfalseиtrue, не совпадают с инициализатором.Поскольку это расширение языка доступно только в C, взаимодействие с другими языками может вызвать трудности. Оно должно корректно взаимодействовать с булевыми типами Ada, определенными с тем же размером и эквивалентными предложениями представления (representation clauses), а также с перечислениями или целочисленными типами других языков, которые соответствуют выбранному в C целочисленному типу.
-
may_alias -
Доступ через указатели на типы с этим атрибутом не подлежит анализу псевдонимов на основе типов (type-based alias analysis), а вместо этого предполагается, что они могут ссылаться на объекты любого другого типа (образовывать псевдонимы). В контексте раздела 6.5, абзаца 7 стандарта C99, выражение lvalue, разыменовывающее такой указатель, обрабатывается так, будто оно имеет символьный тип (character type). Дополнительную информацию о проблемах с псевдонимами см. в описании опции -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 и выше. -
mode (mode) -
Этот атрибут задает тип данных для объявления — тот тип, который соответствует режиму mode. Это фактически позволяет запрашивать целочисленный или вещественный тип в соответствии с его шириной.
Список возможных ключевых слов для mode см. в разделе Machine Modes руководства по внутреннему устройству GNU Compiler Collection (GCC Internals). Вы также можете указать режим
byteили__byte__, чтобы указать режим, соответствующий однобайтовому целого числу,wordили__word__для режима одношинного (однословного) целого числа, иpointerили__pointer__для режима, используемого для представления указателей. -
objc_root_class (Objective-C and Objective-C++ only) -
Этот атрибут помечает класс как корневой класс, что позволяет компилятору опускать любые предупреждения об отсутствующем суперклассе и выполнять дополнительные проверки обязательных методов по мере необходимости.
-
packed -
Этот атрибут, добавленный к определению типа
struct,unionилиclassв C++, указывает, что каждый из его членов (кроме битовых полей нулевой ширины) размещается так, чтобы минимизировать требуемую память. Это эквивалентно указанию атрибутаpackedдля каждого из членов.При добавлении к определению
enumатрибут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илиclass, но не дляtypedef, который одновременно не определяет перечислимый тип, структуру, объединение или класс. -
scalar_storage_order ("endianness") -
При добавлении к
unionилиstructэтот атрибут задает порядок хранения (storage order), он же порядок байтов (endianness), для скалярных полей типа, а также для полей массива, компонентом которых является скаляр. Поддерживаемые порядки байтов:big-endianиlittle-endian. Атрибут не влияет на поля, которые сами по себе являютсяunion,structили массивом, компонентом которого являетсяunionилиstruct; такие поля могут иметь отличный от объемлющего типа порядок хранения скаляров.Обратите внимание, что ни указатели, ни векторные поля в данном контексте не считаются скалярными полями, поэтому атрибут на них не влияет.
Этот атрибут поддерживается только для целевых платформ, использующих единообразный порядок хранения скаляров по умолчанию (к счастью, большинство из них так и делают), то есть платформ, которые сохраняют скаляры либо все в порядке от старшего к младшему (big-endian), либо все в порядке от младшего к старшему (little-endian).
Для типов с обратным порядком хранения скаляров по отношению к порядку хранения по умолчанию на целевой платформе действуют дополнительные ограничения:
- Взятие адреса скалярного поля
unionилиstructс обратным порядком хранения скаляров не допускается и приводит к ошибке. - Взятие адреса поля массива, компонентом которого является скаляр, у
unionилиstructс обратным порядком хранения скаляров разрешено, но выдает предупреждение, если не указан флаг -Wno-scalar-storage-order. - Взятие адреса
unionилиstructс обратным порядком хранения скаляров разрешено.
Эти ограничения существуют потому, что атрибут порядка хранения теряется при взятии адреса скаляра или адреса массива со скалярным компонентом, поэтому косвенное сохранение через этот адрес обычно не работает. Второй случай тем не менее разрешен для возможности выполнения блочного копирования из массива или в массив.
Более того, использование «истолкования типов» (type punning) или переприсваивания псевдонимов (aliasing) для переключения порядка хранения не поддерживается; иными словами, если к определенному скалярному объекту можно получить доступ через различные типы, которые присваивают ему разный порядок хранения, поведение является неопределенным.
- Взятие адреса скалярного поля
-
strub -
Этот атрибут определяет свойства очистки стека (stack-scrubbing) для функций и переменных, благодаря чему функции, работающие с конфиденциальными данными, могут обнулять свои стековые фреймы при возврате управления или пробросе исключений. Это может быть включено явно путем выбора определенных режимов
strubдля конкретных функций или неявно с помощью переменныхstrub.Будучи атрибутом типа, он прикрепляется к типам даже при указании в объявлениях функций и переменных. При применении к типам функций он принимает необязательный строковый аргумент. При применении к типу «указатель на функцию», если задан необязательный аргумент, он распространяется на тип функции.
/* A strub variable. */ int __attribute__ ((strub)) var; /* A strub variable that happens to be a pointer. */ __attribute__ ((strub)) int *strub_ptr_to_int; /* A pointer type that may point to a strub variable. */ typedef int __attribute__ ((strub)) *ptr_to_strub_int_type; /* A declaration of a strub function. */ extern int __attribute__ ((strub)) foo (void); /* A pointer to that strub function. */ int __attribute__ ((strub ("at-calls"))) (*ptr_to_strub_fn)(void) = foo;Функция, связанная с режимом
at-callsstrub(strub("at-calls")или простоstrub), претерпевает изменения интерфейса. Ее вызывающие стороны настраиваются в соответствии с этими изменениями, чтобы очищать (перезаписывать нулями) пространство стека, используемое вызываемой функцией, после ее возврата. Изменение интерфейса делает тип функции несовместимым с простым, но в остальном эквивалентным типом, поэтому каждое объявление и каждый тип, который может использоваться для вызова функции, должны быть связаны с этим режимом очистки (strub mode).Функция, связанная с режимом
internalstrub(strub("internal")), сохраняет неизмененный, совместимый по типу интерфейс, но может быть превращена в обертку (wrapper), которая вызывает обернутое тело с использованием пользовательского интерфейса. Затем обертка очищает пространство стека, используемое обернутым телом. Хотя пространство стека обернутого тела очищается, сама обертка этого не делает, поэтому аргументы и возвращаемые значения могут оставаться неочищенными даже тогда, когда такая функция вызывается другой функцией, включающейstrub. Именно поэтому при компиляции с опцией -fstrub=strict контекстуstrubзапрещено вызывать функцииinternalstrub./* A declaration of an internal-strub function. */ extern int __attribute__ ((strub ("internal"))) bar (void); int __attribute__ ((strub)) baz (void) { /* Ok, foo was declared above as an at-calls strub function. */ foo (); /* Not allowed in strict mode, otherwise allowed. */ bar (); }Автоматически выделяемая переменная, связанная с атрибутом
strub, приводит к тому, что (непосредственно) объемлющая функция включаетstrub.Статически выделяемая переменная, связанная с атрибутом
strub, приводит к тому, что функции, которые читают ее через ее тип данныхstrub, получают включенный режимstrub. Чтение данных путем разыменования указателя на тип данныхstrubимеет тот же эффект. Примечание: Атрибут не переносится из составного типа на типы его компонентов, поэтому желаемый эффект может не достигаться для нескалярных типов.При выборе режима с поддержкой
strubдля функции, которая явно с ним не связана, из-за переменныхstrubили указателей данных, функция должна удовлетворять требованиям жизнеспособности режимаinternal(см. ниже), даже если режимat-callsтакже жизнеспособен и, будучи более эффективным, в итоге выбирается в качестве оптимизации./* zapme is implicitly strub-enabled because of strub variables. Optimization may change its strub mode, but not the requirements. */ static int zapme (int i) { /* A local strub variable enables strub. */ int __attribute__ ((strub)) lvar; /* Reading strub data through a pointer-to-strub enables strub. */ lvar = * (ptr_to_strub_int_type) &i; /* Writing to a global strub variable does not enable strub. */ var = lvar; /* Reading from a global strub variable enables strub. */ return var; }Контекст
strub— это тело (в отличие от интерфейса) функции, для которой включен режимstrub, будь то явно (через режимat-callsилиinternal) или неявно (из-за переменныхstrubили опций командной строки).Функция типа, связанного с режимом
disabledstrub(strub("disabled")), не будет очищать собственное пространство стека. Такие функции не могут вызываться из контекстовstrub.Чтобы разрешить вызов функции из контекстов
strubбез очистки ее пространства стека, свяжите ее с режимомcallablestrub(strub("callable")).Когда функции явно или неявно не назначен режим
strub, по умолчанию используется режимcallable, за исключением случаев компиляции с параметром -fstrub=strict, при котором режимомstrubпо умолчанию становитсяdisabled.extern int __attribute__ ((strub ("callable"))) bac (void); extern int __attribute__ ((strub ("disabled"))) bad (void); /* Implicitly disabled with -fstrub=strict, otherwise callable. */ extern int bah (void); int __attribute__ ((strub)) bal (void) { /* Not allowed, bad is not strub-callable. */ bad (); /* Ok, bac is strub-callable. */ bac (); /* Not allowed with -fstrub=strict, otherwise allowed. */ bah (); }Типы функций, помеченные как
callableиdisabled, не являются взаимно совместимыми типами, но лежащие в их основе интерфейсы совместимы, поэтому безопасно преобразовывать указатели между ними и использовать такие указатели или альтернативные объявления для их вызова. Интерфейсы также взаимозаменяемы между ними иinternal(но неat-calls!), однако добавлениеinternalк типу указателя не приведет к тому, что функция, на которую указывает этот указатель, будет выполнять очистку стека.void __attribute__ ((strub)) bap (void) { /* Assign a callable function to pointer-to-disabled. Flagged as not quite compatible with -Wpedantic. */ int __attribute__ ((strub ("disabled"))) (*d_p) (void) = bac; /* Not allowed: calls disabled type in a strub context. */ d_p (); /* Assign a disabled function to pointer-to-callable. Flagged as not quite compatible with -Wpedantic. */ int __attribute__ ((strub ("callable"))) (*c_p) (void) = bad; /* Ok, safe. */ c_p (); /* Assign an internal function to pointer-to-callable. Flagged as not quite compatible with -Wpedantic. */ c_p = bar; /* Ok, safe. */ c_p (); /* Assign an at-calls function to pointer-to-callable. Flaggged as incompatible. */ c_p = bal; /* The call through an interface-incompatible type will not use the modified interface expected by the at-calls function, so it is likely to misbehave at runtime. */ c_p (); }Контексты
Strubникогда не встраиваются (inlined) в не-strubконтексты. Когда функция с очисткой стека типаinternalразбивается на части, обертка часто может быть встроена, но обернутое тело — никогда. Функция, отмеченная какalways_inline, даже если ей явно назначен режим очисткиinternal, не будет подвергаться обертке, поэтому ее тело будет встроено надлежащим образом.inline int __attribute__ ((strub ("at-calls"))) inl_atc (void) { /* This body may get inlined into strub contexts. */ } inline int __attribute__ ((strub ("internal"))) inl_int (void) { /* This body NEVER gets inlined, though its wrapper may. */ } inline int __attribute__ ((strub ("internal"), always_inline)) inl_int_ali (void) { /* No internal wrapper, so this body ALWAYS gets inlined, but it cannot be called from non-strub contexts. */ } void __attribute__ ((strub ("disabled"))) bat (void) { /* Not allowed, cannot inline into a non-strub context. */ inl_int_ali (); }Некоторые опции командной строки -fstrub=* включают режимы
strubнеявно, где это жизнеспособно. Режимstrubжизнеспособен для функции только в том случае, если функция подходит для этого режима и если выполнены другие условия, описанные ниже. Если функция не подходит для режима, попытки явно связать ее с этим режимом отклоняются с сообщением об ошибке. Если она подходит, этот режим может быть назначен явно с помощью этого атрибута, но неявное назначение с помощью опций командной строки может повлечь за собой дополнительные требования жизнеспособности.Функция не подходит для режима
at-callsstrub, если явно запрошен другой режимstrub, если присутствует атрибутnoipaили если она вызывает__builtin_apply_args. РежимAt-callsstrub, если он не запрошен через тип функции, жизнеспособен для подходящей функции только в том случае, если функция не видна другим единицам трансляции, если ее адрес не берется и если она никогда не вызывается с переопределением типа функции./* bar is eligible for at-calls strub mode, but not viable for that mode because it is visible to other units. It is eligible and viable for internal strub mode. */ void bav () {} /* setp is eligible for at-calls strub mode, but not viable for that mode because its address is taken. It is eligible and viable for internal strub mode. */ void setp (void) { static void (*p)(void); = setp; }Функция не подходит для режима
internalstrub, если явно запрошен другой режимstrubили если присутствует атрибутnoipa. Для функцииalways_inlineвыполнение этих требований достаточно для того, чтобы сделать ее подходящей. Любая функция, которая имеет атрибутnoclone, которая использует такие расширения, как нелокальные метки, вычисляемые переходы (computed gotos), альтернативные интерфейсы передачи переменных аргументов,__builtin_next_argили__builtin_return_address, или которая принимает слишком много (около 64 КБ) аргументов, не подходит, если только она не являетсяalways_inline. Для режимаinternalstrubвсе подходящие функции жизнеспособны./* flop is not eligible, thus not viable, for at-calls strub mode. Likewise for internal strub mode. */ __attribute__ ((noipa)) void flop (void) {} /* flip is eligible and viable for at-calls strub mode. It would be ineligible for internal strub mode, because of noclone, if it weren't for always_inline. With always_inline, noclone is not an obstacle, so it is also eligible and viable for internal strub mode. */ inline __attribute__ ((noclone, always_inline)) void flip (void) {} -
transparent_union -
Этот атрибут, добавленный к определению типа
union, указывает, что любой параметр функции, имеющий этот тип объединения, приводит к тому, что вызовы этой функции обрабатываются особым образом.Во-первых, аргумент, соответствующий прозрачному типу объединения (transparent 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); } -
unavailable unavailable (msg)-
Атрибут
unavailableведет себя так же, как иdeprecated, но выдает ошибку, а не предупреждение. Он используется для указания того, что (возможно, ранее объявленный какdeprecated) тип больше не пригоден для использования.Атрибут
unavailableтакже может использоваться для функций и переменных (см. Объявление атрибутов функций, см. Указание атрибутов переменных). -
unused -
При добавлении к типу (включая
unionилиstruct) этот атрибут означает, что переменные этого типа предполагаются потенциально неиспользуемыми. GCC не создает предупреждений для любых переменных этого типа, даже если переменная кажется не выполняющей никаких действий. Часто это происходит с классами блокировок или потоков, которые обычно определяются, а затем на них не ссылаются, но они содержат конструкторы и деструкторы, выполняющие нетривиальные служебные функции. -
vector_size (bytes)
-
Этот атрибут задаёт размер вектора для типа, измеряемый в байтах. Тип, к которому он применяется, называется базовым типом. Аргумент bytes должен быть положительным кратным размера базового типа, равным степени двойки. Например, следующие объявления:
typedef __attribute__ ((vector_size (32))) int int_vec32_t ; typedef __attribute__ ((vector_size (32))) int* int_vec32_ptr_t; typedef __attribute__ ((vector_size (32))) int int_vec32_arr3_t[3];
определяют
int_vec32_tкак тип вектора размером 32 байта, состоящий из элементов размеромint. Поскольку размерintсоставляет 4 байта, тип задаёт вектор из восьми элементов по четыре байта каждый. Режим переменных типаint_vec32_t—V8SI.int_vec32_ptr_tопределяется как указатель на такой тип вектора, аint_vec32_arr3_t— как массив из трёх таких векторов. Подробнее о работе с объектами векторных типов см. в разделе Использование векторных инструкций через встроенные функции.Этот атрибут применим только к скалярным целочисленным типам и типам с плавающей точкой. В объявлениях функций атрибут применяется к типу возвращаемого значения функции.
Например, следующий код:
__attribute__ ((vector_size (16))) float get_flt_vec16 (void);
объявляет
get_flt_vec16функцией, возвращающей вектор размером 16 байт с базовым типомfloat. -
visibility -
В C++ атрибут видимости (см. раздел Объявление атрибутов функций) также можно применять к типам class, struct, union и enum. В отличие от других атрибутов типов, этот атрибут должен располагаться между начальным ключевым словом и именем типа; его нельзя указывать после тела типа.
Обратите внимание, что видимость типа применяется к сущностям класса со слабой компоновкой, например к таблице виртуальных функций, узлу typeinfo и т. д. В частности, если исключение класса выбрасывается в одном общем объекте и перехватывается в другом, класс должен иметь видимость по умолчанию. В противном случае два общих объекта не смогут использовать один и тот же узел typeinfo, и обработка исключений будет нарушена.
-
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, например: «warning: alignment 4 of 'struct foo' is less than 8». Этот атрибут используется для определенияstruct fooтаким образом, чтобыstruct fooимел ту же структуру, а поле структурыx— такое же выравнивание, когда__u64выровнен по границе в 4 или 8 байт. Выравниваниеstruct fooпо границе в 8 байт:struct __attribute__ ((aligned (8))) foo { int i1; int i2; __u64 x; };подавляет предупреждение. Компилятор также выдаёт предупреждение, например: «warning: 'x' offset 12 in 'struct foo' isn't aligned to 8», если поле структуры имеет смещённое положение:
struct __attribute__ ((aligned (8))) foo { int i1; int i2; int i3; __u64 x; };Это предупреждение можно отключить с помощью -Wno-if-not-aligned.
Чтобы указать несколько атрибутов, разделите их запятыми внутри двойных скобок. Например: «__attribute__ ((aligned (16), packed))».
© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-15.3.0/gcc/Common-Type-Attributes.html