Структуры, typedef, объединения и перечисления
Структуры
Структура объединяет несколько полей разных типов в один объект:
struct point {
int x;
int y;
};
struct point p = {3, 4}; /* инициализация по порядку */
struct point q = {.y = 1}; /* именованная, x = 0 */
p.x = 10; /* доступ к полю */
struct point *pp = &p;
pp->y = 20; /* через указатель: то же, что (*pp).y */
typedef
typedef даёт типу короткое имя. Так в экзаменационной задаче объявлена структура разделяемой памяти:
typedef struct
{
int state; /* свободное поле — подсказка: пригодится для синхронизации */
unsigned int counter;
pid_t pid;
pid_t ppid;
} Mem;
Mem *mem = mmap(NULL, sizeof(Mem), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
mem->counter = 0;
Без typedef пришлось бы везде писать struct имя.
Задача 8, пункт (b)
Условие разрешает добавлять поля в разделяемую память. Это значит, что в Mem можно дописать семафоры (sem_t), массивы, счётчики — всё, что нужно для синхронизации процессов.
Выравнивание
Процессору удобнее читать int по адресу, кратному 4, а double — кратному 8. Компилятор вставляет между полями пустые байты:
Правила: каждое поле выравнивается по своему размеру, а размер всей структуры кратен самому строгому выравниванию среди полей. Смещение поля можно узнать макросом offsetof(struct S, d) из <stddef.h>.
Объединения
union value {
int i;
double d;
char bytes[8];
}; /* sizeof = 8: все поля начинаются с одного адреса */
union value v;
v.d = 1.0;
printf("%02x\n", (unsigned char)v.bytes[7]); /* посмотреть байты double */
В системном коде объединения используются, когда объект хранит одно из нескольких представлений. Например, в ядре Linux в структуре индексного дескриптора есть объединения для данных разных типов файлов, а union sigval передаёт с сигналом реального времени либо число, либо указатель.
Перечисления
enum state { FREE, FULL }; /* FREE = 0, FULL = 1 */
enum color { RED = 1, GREEN = 2, BLUE = 4 };
Константы перечисления — обычные целые числа, но с говорящими именами.
Битовые поля
struct pte { /* упрощённая запись таблицы страниц i386 */
unsigned present : 1; /* P — страница в памяти */
unsigned rw : 1; /* R/W — разрешена запись */
unsigned user : 1; /* U/S — доступна из режима пользователя */
unsigned pwt : 1;
unsigned pcd : 1;
unsigned accessed : 1; /* A — бит доступа */
unsigned dirty : 1; /* D — бит грязности */
unsigned pat : 1;
unsigned global : 1;
unsigned avail : 3;
unsigned frame : 20; /* номер физического кадра */
}; /* ровно 32 бита */
Так удобно описывать аппаратные структуры. Биты accessed и dirty мы подробно разберём в модуле о виртуальной памяти — это задача 5 экзамена.
Итог
- Структура — набор полей;
.для объекта,->для указателя. typedef struct {...} Mem;— короткое имя типа.- Компилятор выравнивает поля;
sizeofструктуры может быть больше суммы полей. union— поля на одном месте;enum— именованные целые; битовые поля описывают аппаратные форматы.
Практика решено 0 из 5
Объявите через typedef структуру Mem с полями: int state, unsigned int counter, pid_t pid, pid_t ppid
— как в задаче 8 экзамена.
typedef struct
{
int state;
unsigned int counter;
pid_t pid;
pid_t ppid;
} Mem;
Чему равен sizeof(Mem) на Linux x86-64, если все четыре поля — по 4 байта (pid_t — это int)?
Чему равен sizeof(struct S) на x86-64?
struct S {
char c;
double d;
char e;
};
Чем объединение (union) отличается от структуры?
Объявите перечисление enum state { FREE, FULL }; и функцию int is_full(const Mem *m),
возвращающую m->state == FULL.
enum state { FREE, FULL };
int is_full(const Mem *m)
{
return m->state == FULL;
}
Войдите, чтобы отмечать пройденные уроки.