ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 13.12.2020
Просмотров: 4259
Скачиваний: 28
Часть I. Язык программирования С
106
{
int a;
struct inside
{
int b;
int c;
} b;
};
int main(void)
{
struct demo c = {1, {2, 3}};
printf("%d %d %d\n", c.a, c.b.b, c.b.c); /* 1 2 3 */
return 0;
}
Так как компилятору должна быть известна длина поля структу-
ры, то в структуре нельзя объявлять член, тип которого совпадает
с типом объявляемой структуры. Однако возможно объявление
члена структуры, тип которого является указателем на тип объяв-
ляемой структуры. Например:
struct node /* вершина двоичного дерева */
{
struct node *left; /* левый потомок */
struct node *right; /* правый потомок */
};
В языке программирования С допускается в качестве последнего
члена структуры объявлять массив неопределенной длины, если
этот массив не является единственным членом структуры. Такие
структуры не могут быть вложены в другую структуру, а также
быть элементами массива. Например:
struct demo
{
double d;
int a[];
};
При объявлении переменной такого типа память под последний
элемент не резервируется. Используются такие структуры для
Глава 8. Типы данных, определяемые программистом
107
обработки структур, последними членами которых являются мас-
сивы различной длины.
Структуры одного типа можно присваивать друг другу. В этом
случае оператор присваивания выполняет почленное копирова-
ние структур. Например:
struct emp boss;
boss = director;
Поля структуры располагаются в памяти последовательно друг за
другом. При этом начальный адрес каждого поля структуры
удовлетворяет условию:
адрес_поля_структуры % длина_поля_структуры == 0
Если поле структуры является массивом, то в этом выражении в
качестве длины поля структуры берут длину элемента массива.
В этом случае говорят, что адреса полей структуры выровнены по
границам соответствующего типа данных. Начальный адрес са-
мой структуры выровнен на границу, кратную наибольшей из
длин полей структуры. Такое выравнивание необходимо для пра-
вильной работы микропроцессора. Отсюда следует, что в струк-
туре могут быть пропущенные байты с неопределенным содер-
жанием. Поэтому работать с полями структуры нужно, используя
их имена.
Отметим, что выравнивание адресов структуры зависит от мик-
ропроцессора, на котором будет работать программа, и поэтому
может отличаться от рассмотренного выше подхода. Обычно
каждый компилятор содержит директиву для управления вырав-
ниванием адресов данных в зависимости от их типа.
8.4. Объединения
Объединением
называется область памяти, используемая для хра-
нения данных разных типов. Причем одновременно в объедине-
нии могут храниться данные только одного определенного типа.
Данные, входящие в объединение, называются
членами объеди-
нения
. Как и в случае структуры, члены объединения могут иметь
любой тип, исключая типы
void
и функцию, при условии, что из-
Часть I. Язык программирования С
108
вестна длина этого типа данных. Тип, описывающий объедине-
ние, также называется
объединением
. Объявляются объединения
следующим образом:
union имя_объединения
{
/* объявления членов объединения */
};
Здесь
union
— ключевое слово, а
имя_объединения
служит для
именования типа объединения и называется
тегом
объединения
,
а члены объединения перечисляются в блоке. Объявление объ-
единения должно заканчиваться символом
;
. Например:
union num
{
int n;
double f;
};
Не допускается объявление
анонимных
объединений.
Тип объединения определяется ключевым словом
union
и тегом
объединения. Поэтому переменная типа объединения объявляет-
ся как:
union имя_объединения имя_переменной;
Например:
union num d; /* d – переменная типа union num */
В языке программирования С++ тип объединения также опреде-
ляется только именем объединения.
Учитывая это замечание, в языке программирования С++ пере-
менную типа объединения можно также объявить следующим
образом:
num d; /* d – переменная типа num */
Объявление типа объединения и переменной, которая имеет этот
тип, может быть объединено в одну инструкцию.
Глава 8. Типы данных, определяемые программистом
109
Например:
union num
{
int n;
double f;
} d; /* d – переменная типа union num */
Допускается объявление переменных, которые имеют тип ано-
нимного объединения. Например:
union
{
int n;
double f;
} d; /* d – переменная типа анонимного объединения */
При объявлении переменной типа объединения ее можно ини-
циализировать значением, которое имеет тип первого члена объ-
единения. Например:
union num d = {10};
Обычно переменные, типом которых является объединение, так-
же называются
объединениями
.
Как и в случае со структурами, для доступа к члену объединения
используется оператор
.
(точка). Например:
union num e;
e.n = 1;
e.f = 1.1;
Объединения одного типа можно присваивать друг другу. В этом
случае оператор присваивания выполняет почленное копирова-
ние объединений. Например:
union num g;
g = e;
Длина памяти, распределяемой компилятором под объединения,
равна наибольшей из длин членов объединения. Адрес этой па-
мяти выравнивается на границу, кратную наибольшей из длин
членов объединения.
Часть I. Язык программирования С
110
8.5. Битовые поля
Битовым полем
называется элемент структуры или объединения,
который определяет последовательность бит и описывается сле-
дующим образом:
тип [имя_поля] : длина_в_битах;
где
тип
может принимать одно из следующих значений:
int
,
unsigned
или
signed
, а
длина_в_битах
должна быть неотрицатель-
ным целым числом. Причем эта длина не должна превышать
длины базового типа данных битового поля. Например:
struct demo
{
int count;
unsigned b1 : 1;
unsigned b2 : 1;
double d;
};
Если длина битового поля равна нулю, то адрес следующего поля
структуры будет выровнен на границу типа
int
.
Запрещается использовать спецификаторы доступа
const
и
volatile
при определении битового поля.
Инициализируются битовые поля, как и обычные члены структу-
ры, например:
struct demo d = {10, 1, 0, 10.5};
Используются битовые поля для установки различных флагов.
Если в программе нужно обрабатывать только некоторые биты из
поля, то остальные биты можно не именовать. В этом случае со-
держимое неименованных битов не определено. Например:
struct demo
{
unsigned b1: 1;
unsigned : 2;
unsigned b2: 1;
};