Spec-Zone.ru › GCC 5

6.39 Указание атрибутов типов

Ключевое слово __attribute__ позволяет указывать специальные атрибуты типов struct и union при определении таких типов. За этим ключевым словом следует спецификация атрибута в двойных скобках. В настоящее время для типов определено восемь атрибутов: aligned, packed, transparent_union, unused, deprecated, visibility, may_alias и bnd_variable_size. Другие атрибуты определены для функций (см. Атрибуты функций), меток (см. Атрибуты меток) и для переменных (см. Атрибуты переменных).

Вы также можете указать любой из этих атрибутов с помощью ‘__’ перед и после его ключевого слова. Это позволяет использовать эти атрибуты в заголовочных файлах, не беспокоясь о возможном макросе с тем же именем. Например, вы можете использовать __aligned__ вместо aligned.

Вы можете указать атрибуты типа в объявлении или определении типа перечисления, структуры или объединения, или для других типов в объявлении typedef.

Для типа перечисления, структуры или объединения вы можете указать атрибуты либо между тегом перечисления, структуры или объединения и именем типа, либо сразу после закрывающей фигурной скобки определения. Предпочтительнее первый синтаксис.

Подробности точного синтаксиса использования атрибутов см. в Синтаксисе атрибутов.

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 может только увеличивать выравнивание, но вы можете уменьшить его, указав packed тоже. Смотрите ниже.

Обратите внимание, что эффективность атрибутов aligned может быть ограничена внутренними ограничениями вашего линкера. На многих системах линкер может только организовать выравнивание переменных до определенного максимального выравнивания. (Для некоторых линков, максимальное поддерживаемое выравнивание может быть очень маленьким.) Если ваш линкер может выровнять переменные только до максимального выравнивания в 8 байт, то указание aligned(16) в атрибуте __attribute__ всё равно обеспечит только выравнивание в 8 байт. Обратитесь к документации вашего линкера для получения дополнительной информации.

packed

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

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

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

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

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

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

visibility

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

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

designated_init

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

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

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

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

6.39.1 Атрибуты типов ARM

На тех целевых платформах ARM, которые поддерживают dllimport (таких как Symbian OS), вы можете использовать атрибут notshared, чтобы указать, что виртуальная таблица и другие подобные данные для класса не должны экспортироваться из DLL. Например:

class __declspec(notshared) C {
public:
  __declspec(dllimport) C();
  virtual void f();
}

__declspec(dllexport)
C::C() {}

В этом коде C::C экспортируется из текущей DLL, но виртуальная таблица для C не экспортируется. (Вы можете использовать __attribute__ вместо __declspec, если предпочитаете, но большинство кода Symbian OS использует __declspec.)

6.39.2 Атрибуты типов MeP

Многие атрибуты переменных MeP могут быть применены и к типам. В частности, атрибуты based, tiny, near, и far могут быть применены к обоим. Атрибуты io и cb не могут быть применены к типам.

6.39.3 Атрибуты типов PowerPC

В настоящее время для конфигураций PowerPC определены три атрибута: altivec, ms_struct и gcc_struct.

Для получения полной документации по атрибутам ms_struct и gcc_struct обратитесь к документации в разделе Атрибуты типов x86.

Атрибут altivec позволяет объявлять типы данных векторов AltiVec, поддерживаемые руководством по программированию AltiVec. Атрибут требует аргумента для указания одного из трех типов векторов: vector__, pixel__ (всегда за которым следует unsigned short), и bool__ (всегда за которым следует unsigned).

__attribute__((altivec(vector__)))
__attribute__((altivec(pixel__))) unsigned short
__attribute__((altivec(bool__))) unsigned

Эти атрибуты предназначены в основном для поддержки ключевых слов AltiVec __vector, __pixel, и __bool.

6.39.4 Атрибуты типов SPU

SPU поддерживает атрибут spu_vector для типов. Этот атрибут позволяет объявлять типы векторных данных, поддерживаемые спецификацией расширений языка SPU Sony/Toshiba/IBM. Он предназначен для поддержки ключевого слова __vector.

6.39.5 Атрибуты типов x86

В настоящее время для конфигураций x86 определены два атрибута: ms_struct и gcc_struct.

ms_struct
gcc_struct

Если packed используется для структуры или используются битовые поля, возможно, Microsoft ABI упаковывает их по-другому, чем GCC. Особенно при перемещении упакованных данных между функциями, скомпилированными с GCC и родным компилятором Microsoft (как через вызов функции, так и в виде данных в файле), может потребоваться доступ к одному из форматов.

В настоящее время для компиляторов Microsoft Windows x86 предоставляется -m[no-]ms-bitfields для соответствия родному компилятору Microsoft.

Далее: Выравнивание, Предыдущее: Атрибуты переменных, Вверх: Расширения C [Оглавление][Индекс]

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

Spec-Zone.ru

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