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

Кроме известных нам типов данных язык Си позволяет создавать еще пять типов данных: структуры (structure), объединения (union), перечислимый тип (enumeration), поля битов (bitfields). Пятая возможность - с помощью оператора typedef создавать новое имя (псевдоним) для уже существующего типа.

Структура в языке Си

Структура – это совокупность взаимосвязанных элементов одного, либо разных типов. Взаимосвязь определяет порядок размещения элементов структуры. Элементы структуры объединены под одним именем. Поэтому структура трактуется не как множество отдельных элементов, а как единое целое.

Примеры структур: библиографические данные о книге; строка платежной ведомости; данные о некотором товаре; координаты точек на плоскости и т. п.;

Над структурами в языке Си стандартом ANSI определены следующие операции:

1. операции присваивания между структурами, имеющими одно и то же имя типа;

2. операции копирования;

3. передача структур в качестве параметров функциям и возврат их в качестве результата;

Кроме этих операций, к структурным переменным применимы следующие:

4. адресная операция &; (кроме битовых полей);

5. операции доступа к элементам структуры “ .” и –> ;

6. инициализация структурных переменных, имеющих класс auto.

В то же время к структурам нельзя применять операции отношения (т.е. нельзя сравнивать структуры).

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

Структура задается в программе структурным шаблоном вида:

struct book

{

char title [40];

char author [30];

float price;

}

Этот шаблон описывает структуру из двух символьных массивов и одной переменной типа float.

Имя book – это имя типа структуры, на которое впоследствии можно ссылаться, как и на имя стандартного типа.

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

struct book libr ;

где struct book – имя_типа, libr – имя_переменной.

Можно объединить определение структурного шаблона и описание структурной переменной, например:

struct book struct

{ {

char title []; float x ;

char author []; float y ;

float price; float z:

} libr ; } coord ;



Можно также проинициализировать структурную переменную. Имя типа структуры можно опустить, т. е.

struct

{

……

……

……

} libr ;

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

libr . title

/ \

имя переменной имя поля

Указатель на структурную переменную может быть задан как:

struct book *ps ;

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

ps-->title;

или ps-->price.

Последняя запись эквивалента (*ps). price.

Создание связанного списка структур осуществляется с помощью следующей конструкции:

struct book

{

char title [ ];

char author [ ];

float price;

struct book *next; /*указатель на следующую строку структуры */

} libr;

Пример 6.1: /* Передача в функцию и возврат целой структурной переменной */

# include

# include

struct book

{ char title [20];

char author [15];

float price;

}; /* внешний шаблон виден всем */

struct book func (struct book); /* прототип функции */

void main (void)

{

struct book lidr_1={“Киселев А.”,

“Избранное”,

4.25}, libr_2;

libr_2=funs (libr_1);

printf (“%-20s %-20s цена -%5.2f \ n”,

libr_1. title, libr_1. author, libr_1. price);

printf (“%-20s %-20s цена -%5.2 f \ n”,

libr_2. title, libr_2. author, libr_2. price);

}

struct book func ( struct book libr)

{ strcpy (libr. title, “Язык Си”);

strcpy (libr. author, “Семенов К.”);

libr. price = 6.36;

return libr; }

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

func1(first. a) ; func2 (&second. b);

Заметим, что & ставится перед именем структуры, а не перед именем поля.

Можно в качестве формального параметра передать по значению всю структуру:

Пример 6.2:

/* Использование структуры в качестве параметра */

include

struct stru {

int x ;

char y ;};

void f(struct stru param ); /* прототип функции */

main (void)

{

struct stru arg ;

arg. x =1;



arg. y = ‘2’;

f(arg) ;

return 0;

}

void f(struct stru param)

{

printf (”%d %d \n”, param. x, param. y ) ;

}

Можно также создать указатель на структуру и передавать аргумент типа структуры по ссылке. Объявить указатель на структуру можно следующим образом:

struct stru *adr_pointer;

struct stru – переменная типа указатель на структуру struct stru.

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

При передаче по ссылке в стек занесется только адрес структуры. При этом копирования структуры не происходит, а такие появляется возможность изменять содержимое элементов структуры.

struct complex {

float x;

float y;} c1, c2;

struct complex *a ; /* объявление указателя */

a = & c1;

Указателю a присвоится адрес переменной с1. Получить значение элемента можно так:

(*а). x ;

Кроме данного способа получить значение, мы можем использовать так же оператор а --> х, который обычно и применяется, т. е. (*а).х эквивалентно а --> х.

Объединения

В языке Си определен еще один тип для размещения в памяти нескольких переменных разного типа. Это – объединение. Объявляется объединение так же, как и структура, например:

union u{

int i ;

char ch ;

long int l ;

};

Это объединение не задает какую-либо переменную. Оно задает шаблон объединения.

Можно объявить переменную:

union u alfa, beta ;

Можно было объявить переменные одновременно с заданием шаблона. В отличие от структуры для переменной типа union места в памяти выделяется ровно столько, сколько надо элементу объединения, имеющему наибольший размер в байтах. Так под переменную alfa будет выделено четыре байта, под переменную i – 2 байта; под переменную ch – 1 байт; под переменную l – 4 байта;

Синтаксис использования элементов объединения такой же, как и для структур:

u.ch = ‘ 5 ‘;

Для объединения разрешена также операция -->, если мы обращаемся к объединению с помощью указателя.

Битовые поля

Структура может содержать битовые поля. Целые компоненты типа signed и unsigned можно объявить битовыми полями шириной от 1 до 16 битов. Ширина битового поля и его необязательный идентификатор задаются следующим образом:

тип : ширина;

где тип - это char, unsigned char, int или unsigned int .

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

Пример:

struct str {

int i: 3;

unsigned j: 4;

int : 4

int k: 2;

} a ;

Для указанных в структуре полей задается следующее распределение памяти:

15 14 12 11 10 9 8 7 6 5 4 3 2 1 0

x x x x x x x x x x x x x x x

k не испол. j i

Целые поля хранятся в виде дополнения до 2, причем крайний левый бит является старшим. Для битового поля типа int (например, signed) старший бит интерпретируется как знаковый. Например, поле k типа signed int шириной 1 может содержать только значения –1 и 0, так как битовой шаблон 1 будет интерпретироваться как -1.

Пример 6.3:

#Include

void main (void)

{

struct str {

int i:1;

unsigned j:4;

int l:4;

int k:2;

} a;

a.i=1;

printf(“%d”,a.i);

}

Результат работы программы: -1.

Доступ к отдельному биту

В отличие от других языков программирования язык Си обеспечивает доступ к одному или нескольким битам в байте или слове. Это имеет свои преимущества. Если многие переменные принимают только два значения, (такие переменные называют флагами), то можно использовать 1 бит.

Один из методов, встроенных в язык Си и позволяющих иметь доступ к биту, – это поля битов (bit-fields). В действительности поля битов – это специальный тип структуры, в котором определено, из каких бит состоит каждый элемент. Основная форма объявления такой структуры следующая:

struct имя_ структуры

{

тип имя 1: длина в битах ;

тип имя 2: длина в битах ;

…………………………. ;

тип имя N: длина в битах ;

}

В этом объявлении структур тип может быть одним из следующих: int, unsigned, signed. Имя I может быть пропущено, тогда соответственно число бит не используется (пропускается). Длина структуры всегда кратна восьми. Так, если указать:

struct onebit

{

unsigned one_bit : 1;

} obj ;

то для переменой obj будет выделено 8 бит, но использоваться будет только первый.


tipi-proizvodstva-formi-organizacii-i-vidi-tehnologicheskih-processov.html
tipi-promishlennogo-proizvodsva.html
    PR.RU™