Spec-Zone.ru › GCC 7

6.33.1 Атрибуты общих типов

Следующие атрибуты типа поддерживаются на большинстве целевых платформ.

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 может быть ограничена внутренними ограничениями вашего линкера. На многих системах линкер может только выровнять переменные до определённого максимального выравнивания. (Для некоторых линков максимальное поддерживаемое выравнивание может быть очень маленьким.) Если ваш линкер может только выровнять переменные до максимального выравнивания 8 байт, то указание aligned(16) в атрибуте __attribute__ по-прежнему обеспечивает только 8-байтовое выравнивание. Для получения дополнительной информации см. документацию вашего линкера.

Атрибут aligned может только увеличить выравнивание. Выравнивание может быть уменьшено, указав атрибут packed. См. ниже.

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
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, который должен быть строкой, печатается в предупреждении, если он присутствует.

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

designated_init

Этот атрибут может быть применён только к типам структур. Он указывает, что любая инициализация объекта этого типа должна использовать обозначенные инициализаторы, а не позиционные. Цель этого атрибута — позволить программисту указать, что структура может измениться, и что поэтому полагаться на позиционные инициализации приведёт к будущим проблемам.

GCC по умолчанию выводит предупреждения на основе этого атрибута; используйте -Wno-designated-init, чтобы подавить их.

may_alias

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

packed

Этот атрибут, прикреплённый к определению типа struct или union, указывает, что каждый член (кроме полей битов нулевой ширины) структуры или объединения размещается для минимизации требуемого объёма памяти. Прикреплённый к определению enum, он указывает, что должен использоваться наименьший целочисленный тип.

Указание атрибута packed для типов 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;
  };

Атрибут packed можно указывать только для определения enum, struct или union, а не для typedef, которое не определяет перечисление, структуру или объединение.

scalar_storage_order ("endianness")

Прикреплённый к union или struct, этот атрибут устанавливает порядок хранения, т. е. порядок байтов, скалярных полей типа, а также полей массива, компонентом которого является скаляр. Поддерживаемые порядки байтов — big-endian и little-endian. Атрибут не оказывает никакого влияния на поля, которые сами являются union, struct или массивом, компонентом которого является union или struct, и эти поля могут иметь другой порядок хранения скаляров, чем в enclosing type.

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

visibility

В C++, атрибут видимости (см. Атрибуты функций) также может применяться к типам классов, структур, объединений и перечислений. В отличие от других атрибутов типа, атрибут должен появляться между исходным ключевым словом и именем типа; он не может появляться после тела типа.

Обратите внимание, что видимость типа применяется к общим ссылкам, связанным с классом (vtable, узел typeinfo и т. д.). В частности, если класс брошен как исключение в одном объекте совместного использования и перехвачен в другом, класс должен иметь видимость по умолчанию. В противном случае два объекта совместного использования не смогут использовать один и тот же узел typeinfo, и обработка исключений будет нарушена.

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

Далее: Атрибуты типов ARM, Наверх: Атрибуты типов [Содержание][Индекс]

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

Spec-Zone.ru

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