Spec-Zone.ru › GCC 11

Следующее: Атрибуты типа ARC, Выше: Указание атрибутов типов [Оглавление][Индекс]

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, возвращает объект, размер которого задается аргументом 1 функции.

copy
copy (expression)

Атрибут copy применяет набор атрибутов, с которыми был объявлен тип выражения, к объявлению типа, к которому применен атрибут. Атрибут предназначен для библиотек, которые определяют псевдонимы, которые, как ожидается, определят тот же набор атрибутов, что и алиасированные символы. Атрибут 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, разыменовывающее такой указатель, обрабатывается как имеющее тип символа. Для получения дополнительной информации о проблемах с алиасами см. -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 см. в разделе «Режим машины» в «Внутренних сведениях о GNU Компиляторе Коллекции (GCC)» по адресу Machine Modes. Вы также можете указать режим byte или __byte__ для указания режима, соответствующего целому числу с одним байтом, word или __word__ для режима целого числа с одним словом и pointer или __pointer__ для режима, используемого для представления указателей.

packed

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

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, и обработка исключений будет нарушена.

objc_root_class (Objective-C and Objective-C++ only)

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

Для указания нескольких атрибутов разделяйте их запятыми внутри двойных скобок: например, «__attribute__ ((aligned (16), packed))».

Далее: Атрибуты типов ARC, Назад: Указание атрибутов типов [Оглавление][Индекс]

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-11.4.0/gcc/Common-Type-Attributes.html

Spec-Zone.ru

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