Расположение структурных переменных в памяти

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

Рассмотрим структуру:

struct {

long L;

int i1, i2;

char c[4];

} STR1;

 

 

В памяти каждый элемент имеет свое место, и размещаются они последовательно:

f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff

                                                           

long L int i1 int i2 char c[4]

 

Компилятор выделяет под структурную переменную STR1 число байтов памяти, достаточное для хранения всех ее полей. Однако выделенное количество байт не всегда равно сумме длин отдельных полейиз-за влияния дополнительного фактора внутреннего представления структурных переменных,называемоговыравниванием.

При выравнивании на границе байта отдельные поля структурной переменной в памяти располагаются без зазоров, с любого четного или нечетного адреса; размер занимаемой структурной переменной памяти равен сумме размеров полей шаблона структуры.

Выравнивание на границе байта устанавливает директива препроцессора #pragma pack(push,n); аргумент n задает выравнивание данных в структурах на n байт ( n=(1,2,4,8,16) ). Отмена директивы: #pragma pack(pop). Директива #pragma pack(show) выводит в качестве warning значение выравнивания по умолчанию, например: value of pragma pack(show) == 8.

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

· отдельная структурная переменная (элемент массива структурных переменных) начинается на границе слова;

· любое поле, тип которого не совпадает с типом char, будет начинаться на границе слова;

· при необходимости в конце структурной переменной добавляются байты.

 

Расположение в памяти структурной переменной STR2при наличии выравнивания на границе слова:

struct {

long L;

char c[3];

int i1, i2;

} STR2;

 
 


f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff

                                                           

long L char c[3] int i1 int i2

Сумма размеров элементов структуры (4+3+4+4=15) меньше, чем отведено структуре в целом (16) из-за того, что размер массива char c[3]; не кратен длине слова компьютера и перед элементом int i1 для выравнивания вставлен пустой байт.

 

Выделенное число байт возвращает операция sizeof .

Инициализация структурных переменных

Разрешается выполнять инициализацию полей структурной переменной при её определении. Например:

struct Book {char name[20]; //определение шаблона структуры

char title[44];

int year;

float price;

};

 

Book// инициализация структурных переменных при их определении
first_book=

{“Mitchel M.”,

“Unesennie vetrom”,

2007,

20000},

child_book=

{“Troepolskij G.”,

“Belij Bim Chernoe Ucho”,

2006,

10000},

dog_book=

{…..};

 

Инициализирующие значения располагаются в порядке объявления полей в структурном типе. Типы инициализирующих значений должны быть совместимы с типами соответствующих полей в определении структурного типа.

 

Вложенные структуры

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

 

Поле, являющееся структурой, называют вложенной структурой. Естественно, что шаблон вкладываемой структуры должен быть уже известен компилятору. Например:

struct UDC {char class, subclass; int number;};

struct Book { struct UDK udc_class;

char name [20];

chat title[44];

int year;

float price;

} first_book, child_book, dog_book;

 

Ссылка на поле вложенной структуры формируется из имени структурной переменной, имени структурного поля и имени вложенной структуры. Перечисленные имена разделяются символом «точка». Например:

first_book.udc_class.class= ‘A’; //(first_book.udc_class).class.

dog_book.udc_class.number=681;

 

Теоретически не существует ограничения на величину уровня вложенности структур.

В отношении полей структурного типа существует только одно существенное ограничение – поле не может иметь тот же тип, что и определяемый структурный тип, однако оно может иметь тип указателя на этот тип.

Например:

struct Book{Book my_s; //это ошибка !!!!!

char name[20];

char title[44];

int year;

float price;

};

struct Book{Book* my_s; //OK!!!!!

char name[20];

char title[44];

int year;

float price;

};

 

Пусть имеем вложенные структуры:

struct Distance //длина в километрах и метрах

{ int km, m;

};

struct Pole //размеры прямоугольного поля

{Distance length;

Distance width,

};

 

Тогда инициализация структурной переменной типа Pole выглядит так:

Pole pole = { {2, 20}, {1, 5}};