Spec-Zone.ru › GCC 9

6.35.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 в другую, что повышает эффективность работы во время выполнения.

Обратите внимание, что выравнивание любого типа struct или union согласно стандарту ISO C должно быть по крайней мере кратным наименьшему общему кратному выравниваний всех членов типа 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 генерирует предупреждение.

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 __attribute__ ((aligned (8))) foo
{
  int i1;
  int i2;
  __u64 x;
};

отключает предупреждение. Компилятор также выводит предупреждение, например, «предупреждение: смещение 'x' 12 в 'struct foo' не выровнено на 8», когда поле структуры имеет невыровненное смещение:

struct __attribute__ ((aligned (8))) foo
{
  int i1;
  int i2;
  int i3;
  __u64 x;
};

Это предупреждение можно отключить с помощью -Wno-if-not-aligned.

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 - это тип функции, которая, как и стандартная функция C calloc, возвращает объект, размер которого задается произведением аргументов 1 и 2, и что malloc_type, как и стандартная функция C malloc, возвращает объект, размер которого задается первым аргументом функции.

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, который должен быть строкой, печатается в предупреждении, если он присутствует. Управляющие символы в строке будут заменены последовательностями экранирования, а если опция -fmessage-length установлена в 0 (ее значение по умолчанию), то любые символы новой строки будут игнорироваться.

Атрибут deprecated также может использоваться для функций и переменных (см. Атрибуты функций, см. Атрибуты переменных).

Сообщение, прикрепленное к атрибуту, зависит от установки опции -fmessage-length.

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 и выше.

mode (mode)

Этот атрибут задает тип данных для объявления — любой тип, соответствующий режиму mode. Это позволяет запросить целочисленный или с плавающей запятой тип в соответствии с его шириной.

См. Режимы машины в документации по внутреннему устройству GNU Компилятора Коллекции (GCC), для списка возможных ключевых слов для mode. Вы также можете указать режим byte или __byte__ для обозначения режима, соответствующего целому числу длиной один байт, word или __word__ для режима целочисленного значения длиной одно слово, и pointer или __pointer__ для режима, используемого для представления указателей.

packed

Этот атрибут, прикрепленный к struct, union, или C++ class определению типа, указывает, что каждый его член (кроме полей битов шириной ноль) размещается для минимизации занимаемой памяти. Это эквивалентно указанию атрибута 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, этот атрибут устанавливает порядок хранения, т.е. порядок байтов, скалярных полей типа, а также полей массивов, компоненты которых являются скалярными. Поддерживаемые порядки байтов — big-endian и little-endian. Атрибут не влияет на поля, которые сами являются union, struct или массивом, компонента которого является union или struct, и эти поля могут иметь порядок хранения скаляров, отличный от порядка хранения окружающего типа.

Этот атрибут поддерживается только для целей, использующих единообразный порядок хранения скаляров по умолчанию (к счастью, большинство из них), т.е. для целей, в которых скаляры хранятся либо в порядке big-endian, либо в порядке little-endian.

Дополнительные ограничения применяются к типам с обратным порядком хранения скаляров относительно порядка хранения скаляров для целевой системы:

  • Взятие адреса скалярного поля union или struct с обратным порядком хранения скаляров запрещено и приводит к ошибке.
  • Взятие адреса поля массива, компонента которого является скалярным, union или struct с обратным порядком хранения скаляров разрешено, но приводит к предупреждению, если не указано -Wno-scalar-storage-order.
  • Взятие адреса union или struct с обратным порядком хранения скаляров разрешено.

Эти ограничения существуют, потому что атрибут порядка хранения теряется при взятии адреса скаляра или адреса массива со скалярной компонентой, поэтому косвенное хранение по этому адресу, как правило, не работает. Тем не менее, второй случай разрешается для выполнения копирования блока из массива или в массив.

Кроме того, не поддерживается использование type punning или алиасирования для переключения порядка хранения; другими словами, к данному скалярному объекту нельзя получить доступ через различные типы, которые назначают ему разный порядок хранения.

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 не выводит предупреждение для переменных этого типа, даже если переменная, кажется, ничего не делает. Это часто происходит с классами блокировки или потоков, которые обычно определяются, а затем не используются, но содержат конструкторы и деструкторы, имеющие функции учёта, которые не являются тривиальными.

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++, атрибут видимости (см. Атрибуты функций) также может быть применён к классам, структурам, объединениям и перечислениям. В отличие от других атрибутов типов, атрибут должен находиться между начальным ключевым словом и именем типа; он не может находиться после тела типа.

Обратите внимание, что видимость типа применяется к сущностям с размытой связью, связанными с классом (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-9.5.0/gcc/Common-Type-Attributes.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API