Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Козак Н.В. Лекции Основы создания программ в Си...doc
Скачиваний:
24
Добавлен:
23.09.2019
Размер:
2.24 Mб
Скачать

Типы, определяемые пользователем

Переименование типов

Любому типу в С можно присвоить простое имя или переименовать его. Это делается с помощью ключевого слова typedef:

typedef тип новое_имя_типа;

Например

ypedef unsigned char BYTE; // 8-bit unsigned entity.

typedef BYTE * PBYTE; // Pointer to BYTE.

typedef char MessageStr[80]; // Имя типа для массивов char[80].

Перечислимые типы

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

Например:

enum Status

{

Success = 1,

Wait,

Proceed,

Error = -1

} stat1, stat2;

Обобщенная запись имеет вид:

enum имя-этикетка {имя__константы- [= значение] , . . . } переменная [, . . .];

В операторе еnum после закрывающей фигурной скобки можно сразу объявить несколько переменных данного типа:'

Имя-этикетка не является настоящим именем типа. Именем типа будет в вышеприведенном примере enum Status.

enum Status ProclStatus, Proc2Status;

Но есть возможность воспользоваться ключевым словом typedef:

typedef enum _Status

{

Success = 1,

Wait,

Proceed,

Error = -1

} Status;

Тогда Status будет полноценным именем перечислимого типа. (Обратите внимание, что для этикетки мы указали имя _status. Это обычная практика.)

Структуры

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

Синтаксис структуры имеет такой вид:

struct этикетка {список_элементов} [переменные];

Вот простой пример структуры, предназначенной для хранения основных сведений о человеке:

struct Person {

char lastName[32]; // Фамилия.

char firstName[32]; // Имя.

Sex sex; //Пол: перечислимый тип [male, female}.

short age; // Возраст.

long phoneNum; // Телефон как длинное целое.

} aPerson; // Объявляет переменную типа struct Person.

Аналогично именем типа является struct этикетка (struct Person), и его можно сразу переопределить с помощью ключевого слова typedef.

Для доступа к отдельным элементам структуры имеются две операции: точка и стрелка, за которыми следует имя элемента. С именем переменной структуры применяется точка, с указателем на переменную структуры используется стрелка:

struct Person *pPerson = &aPerson; // Указатель на структуру.

aPerson.age = atol (ageStr); // Записать в структуру возраст

aPerson.sex = male; // и т.д.

pPerson->phoneNum = atol (phoneStr);

/* Напечатать имя и фамилию

(предполагается, что они уже инициализированы). */

printf("%s %s\n", pPerson->firstName, pPerson->lastName);

Битовые поля

В качестве элементов структуры можно определять битовые поля. Для них задается ширина поля в битах, и компилятор отводит под элемент ровно столько бит, сколько указано. Несколько битовых полей может быть таким образом упаковано в одном слове (2 байта). Синтаксис битового поля:

тип [имя_поля] : ширина__поля;

Тип поля может быть int или unsigned int. Доступ к битовым полям осуществляется так же, как и к регулярным элементам структуры. Если имя_поля отсутствует, место под поле отводится, но оно остается недоступным. Это будут просто «заполняющие» биты.

struct BitsFields // структура битовых полей в рамках одного байта

{

int Field1 : 1;

unsigned UnsignedField1 : 3;

int : 3 // заполняющие биты

unsigned UnsignedField2 : 1;

};

BitsFields QWE;

:::::

QWE.CharField = 100;

QWE.IntField = 101;

QWE.UnsignedField = 1;

Битовые поля применяются либо там, где необходима плотная упаковка ин­формации (как это бывает при передаче функции некоторого набора логических флагов), либо, например, для отображения регистров внешнего устройства, которые часто бывают организованы как совокупность небольших полей и отдельных битов.

Объединения

Объединения, определяемые с помощью ключевого слова union, похожи по своему виду на структуры:

union этикетка {список_элементов} [переменные];

Отличие состоит в том, что все элементы объединения занимают одно и то же место в памяти, они перекрываются. Компилятор отводит под объединение память, достаточную для размещения наибольшего элемента. Объединения полезны, когда требуется обеспечить своего рода «полиморфное поведение» некоторого объекта. Например, вы хотите определить тип, реализующий представление различных геометрических фигур — прямоугольников, окружностей, линий, многоугольников. В зависимости от того, чем конкретно является данная фигура, для ее описания необходимы различ­ные наборы значений.

/* Тип для определения вида объекта */

typedef enum

{

Rect=l,

Labi

} Type;

/*Структура для хранения прямоугольников и текстовых меток. */

typedef struct _GForm

{

Type type;

struct _GForm *next; /* Указатель для связанного списка. */

union /* Анонимное объединение. */

{

struct /* Прямоугольник. */

{

int left, top;

int right, bottom;

} rect;

struct /* Текстовая метка. */

{

int x, у;

char text[20];

} labl;

} data;

} GForm;

Использование переменных

/* Инициализация первого объекта. */

forml.type = Rect;

forml.data.rect.left = 50;

forml.data.rect.top = 25;

forml.data.rect.right = 100;

forml.data.rect.bottom = 75;

/* Инициализация второго объекта.

form2.type = Labl;

form2.data.labl.x = 60;

form2.data.labl.у = 40;

strcpy(form2.data.labl.text, "This is a Label!");

Структура _GForm имеет, как таковая, три элемента: type, next (не используется) и data.