Struct mystruct

{

int i;

char str[21];

double d;

} s, *sptr=&s;

...

s.i = 3; // присвоение члену i структуры mystruct s;

sptr->d = 1.23; // присвоение компоненту d структуры mystruct s;

Если структура B содержит поле, тип которого есть структура A, то доступ к компонентам A выполняется через два одновременно задаваемых выбора компонента структуры. Например:

Struct A

{

int j;

double x;

};

Struct B

{

int i;

struct A a;

double d;

} s, *sptr;

...

s.i = 3; // присвоение компоненту i структуры B

s.a.j = 2; // присвоение компоненту j структуры A

sptr->d = 1.23; // присвоение компоненту d структуры B

(sptr->).x = 3.14 // присвоение компоненту x структуры A

Каждое объявление структуры вводит уникальный тип, поэтому в структуре:

Struct A

{

int i,j;

double d;

} a, a1;

Struct B

{

int i,j;

double d;

} b;

объекты a и a1 оба имеют тип struct A, но объекты a и b имеют различные типы структуры.

Структурам могут присваиваться значения только в том случае, если и исходная структура, и структура назначения имеют один и тот же тип. Например:

a = a1; // так можно; тип один и тот же, поэтому может быть

// выполнено покомпонентное присвоение структур;

a = b; // так нельзя; различные типы;

a.1 = b.1; a.j = b.j; a.d = b.d; // такое присваивание на

// уровне компонентов структуры можно выполнять;

Память распределяется в структуре покомпонентно, слева направо, от младшего к старшему адресу памяти. В следующем примере:

struct mystruct {

int i;

char str[21];

double d;

} s;

объект s занимает достаточное количество памяти для размещения целочисленного значения типа int, 21-байтовой строки и 8-байтового значения типа double.

Имена тегов структур разделяют общее пространство имен с тегами объединений и перечислений (однако в языке С++ имена входящих в структуру перечислений находятся в другом адресном пространстве). Это означает, что в пределах одного контекста такие теги должны иметь уникальные имена. Тем не менее, имена тегов не обязаны отличаться от идентификаторов, находящихся в трех других адресных пространствах: пространстве имен меток, пространстве имен компонентов и едином адресном пространстве.

Имена компонентов в пределах данной структуры или объединения обязаны быть уникальными, но среди разных структур или объединений они могут совпадать. Например:

goto s;

...

s: struct s { // так можно; теги и имена меток находятся в разных адресных пространствах;

int s // так можно; теги, имена меток и имена компонентов находятся в разных адресных пространствах;

float s; // так нельзя: повторение имени компонентов структур;

} s; /* так можно; пространства имен переменных различны. В языке С++ это допустимо только если s не имеет конструктора */

union s { // так нельзя: повторение имен в пространстве тегов;

int s; // так можно: новое пространство компонентов;

float f;

} f; // так можно: пространство имен переменных;

 

struct t {

int s; // так можно: следующее пространство имен компонентов;

...

} s; // так нельзя: повторение имен переменных

Указатель на структуру типа А допустим в объявлении другой структуры В до объявления структуры А. Например:

struct A; // неполное объявление;

struct B { struct A *pa };

struct A { struct B *pb };

Первое объявление А называется неполным, поскольку в этой точке отсутствует определение А. В данной ситуации неполное объявление допустимо, поскольку в объявлении В размер А необязателен.

Структура может содержать любые комбинации битовых полей с данными других типов.

Целочисленные компоненты типа signed или unsigned можно объявить битовыми полями шириной от 1 до 16 бит. Ширина битового поля и его опциональный идентификатор задаются следующим образом:

Спецификатор_типа <идентификатор-битового поля>:ширина;

где спецификатор_типа это char, unsigned char, int или unsigned int. Битовые поля располагаются, начиная с младшего и кончая старшим битом слова. Выражение "ширина" должно быть задано и должно давать целочисленную константу со значением в диапазоне от 1 до 16.

Если идентификатор битового поля опущен, то число битов, заданное выражением "ширина", распределяется в памяти, но поле при этом остается недоступным программе. Это позволяет создавать битовые шаблоны для, например, аппаратных регистров компьютера, в которых некоторые биты не используются. Например, структура

struct mystruct {

int i:2;

unsigned j:5;

int :4;

int k:1;

unsigned m:4;

} a, b, c;

создает следующее распределение памяти:

 
 

Для битового поля типа int (например, signed) старший бит интерпретируется как знаковый бит. Битовое поле шириной 2, содержащее двоичное 11, будет, следовательно, в случае типа unsigned интерпретироваться как 3, а в случае int как -1. В данном примере выражение a.i = 6 поместит в a.i двоичное 10 = -0, не выдавая каких-либо предупреждений. Поле k типа signed int шириной 1 может содержать только значения 1 и 0, так как битовый шаблон 1 будет интерпретирован как «минус» (-).

Примечание: Битовые поля могут быть объявлены только в структурах, объединениях и классах. Доступ к ним выполняется тем же способом выбоpа компонентов (.) и (->), что и для небитовых компонентов. Битовые поля вызывают некоторые проблемы, когда записывается переносимый код, поскольку организация битов в байтах и байтов в словах зависит от конкретной машины. Выражение &mystruct.x недопустимо, так как x – это идентификатор битового поля, и никакой гарантии, что mystruct.x имеет адрес на границе байта, нет.