Изучая структуры, имеет смысл обращать внимание на их представление в памяти компьютера. Порядок описания полей в определении структурного типа задаёт порядок их расположения в памяти.
Рассмотрим структуру:
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 }};