Spec-Zone.ru › GCC 8

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 . См. ниже.

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

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

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

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

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

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

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

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

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

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

Spec-Zone.ru

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