- Способы определения типа данных
- Контекстное определение типа данных в Си
- Иерархия типов данных и переменных
- Функция как тип данных
- Указатель на массив
- Вопросы без ответов
- Определение типа данных в ячейке или переменной
- Способ 1. Использовать функцию TypeName для определения типа данных
- Способ 2. Проверка на возможность преобразования строки к нужному типу.
- Типы Данных И Их Объявление
- 1.2.1 Категории типов данных
- 1.2.2. Целый тип данных
- 1.2.3. Данные плавающего типа
- 1.2.4. Указатели
- 1.2.5. Переменные перечислимого типа
- 1.2.6. Массивы
- 1.2.7. Структуры
- 1.2.8. Объединения (смеси)
- 1.2.9. Поля битов
- 1.2.10. Переменные с изменяемой структурой
- 1.2.11. Определение объектов и типов
- 1.2.12. Инициализация данных
Способы определения типа данных
Настало время свести воедино все интуитивно используемые понятия, касающиеся организации данных — типов данных, переменных. Язык Си имеет здесь свою специфику. Во-первых, он является жестко типизированным с привязкой при трансляции к каждому объекту (переменной) раз и навсегда заданных типов данных. Во-вторых, способ определения этого типа довольно специфичен: он задается неявно, в контексте (окружении) тех операций, которые можно выполнить над объектом. Это создает дополнительную путаницу у начинающих: они зачастую путают синтаксис использования переменной в выражении и синтаксис ее определения, путают определение с объявлением, поскольку в том и другом случае применяются одни и те же операции, один и тот же синтаксис.
Контекстное определение типа данных в Си
Вся мебель в ней дубовая.
Вот это стул — на нём сидят.
Вот это стол — за ним едят.
Идея контекстного определения типа данных состоит в том, что определяемая переменная помещается в контекст (окружение) тех операций, с которыми она может быть использована. В более широком плане это восходит к способу определения предметов через действия, которые над ними можно произвести, т.е. «автомобиль – это то, на чем ездят». Поскольку речь идет об определении переменных производного типа данных, то операции, которые применимы к нему – это не арифметические и им подобные, а операции выделения составляющего типа данных. Если при классификации операций исходить из их функционального назначения, то для переменной каждого производного типа данных можно выделить операцию, при помощи которой можно добраться до составляющих ее компонент.
Использование в контекстном определении
* p — переход к указуемому объекту, разыменование
& a — получение указателя (взятие адреса)
Таким образом, если в контексте (окружении) переменной встречается такая операция, то можно догадаться, к какому производному типу данных относится сама переменная. Поэтому контекстное определение переменной использует эти операции следующим образом :
· определение переменной содержит имя переменной в окружении (контексте) операций выделения составляющего типа данных, последовательно выполняемых над ней;
· допустимыми операциями являются [] – для массива, * — для указателя и () – для функции. Кроме того, используются приоритетные скобки;
· операции записываются в той последовательности, в которой они могут быть применены к переменной, с учетом их естественных приоритетов. Для изменения естественной последовательности могут использоваться приоритетные скобки ;
· в результате последовательного применения указанных операций получается тип данных, стоящий слева в определении.
Контекстное определение типа понимается следующим образом. Если взять переменную некоторого неизвестного пока типа данных и выполнить над ней последовательность операций выделения составляющих типов данных, то в результате получится переменная того типа данных, который указан в левой части определения. При этом должны соблюдаться приоритеты выполнения операций, а для их изменения использоваться круглые скобки. Полученная последовательность выполнения операций дает обратную последовательность определений типов от базового к производному, начиная с типа, стоящего слева. Рассмотрим несколько примеров.
переменная, при косвенном обращении к которой получается целое -указатель на целое (прямая цепочка типов указатель – int , обратная — int — указатель).
Переменная, которая является массивом, при косвенном обращении к элементу которого получаем указатель на символ (строку) — массив указателей на символы (прямая цепочка типов массив – указатель – char , обратная – char – указатель — массив).
переменная, при косвенном обращении к которой получается двумерный массив, состоящий из массивов по 80 символов — указатель на двумерный массив строк по 80 символов в строке (прямая цепочка типов указатель – двумерный массив — char )..
переменная, при косвенном обращении к которой получается вызов функции, возвращающей в качестве результата целое — указатель на функцию, возвращающую целое (прямая цепочка типов указатель – функция — int )..
переменная, которая является массивом, при косвенном обращении к элементу которого получается вызов функции, возвращающей целое -массив указателей на функции, возвращающих целое (прямая цепочка типов массив — указатель – функция — int )..
переменная, при косвенном обращении к которой получается вызов функции, при косвенном обращении к ее результату получается вызов функции, которая в качестве результата возвращает переменную, при косвенном обращении к которой получается символ. Тип переменной p — указатель на функцию, возвращающую в качестве результата указатель на функцию, возвращающую указатель на строку (прямая цепочка типов указатель – функция – указатель – функция – указатель — char ).
Естественно, что не все сочетания типов данных допустимы, а только те, которые напрямую представимы в компьютерной архитектуре (что следует из свойств самого Си). Например, массив указателей (адресов) функций допустим, а массив функций – нет, поскольку адреса (указатели) имеют фиксированную размерность и допускают копирование, а тип данных – функция допускает только вызов.
void (* pp [10])(); // Массив указателей на функции — допустимо
void ( pp [10])(); // Массив функций – что это такое.
Синтаксис контекстного определения не ограничивается обычными переменными. Он появляется всегда, когда речь заходит о типизированных компонентах программы. По правилам контекстного определения записываются :
· определения и описания переменных;
· формальные параметры функций;
· определения элементов структуры ( struct);
· определения абстрактных типов данных;
· определения промежуточных типов данных (спецификатор typedef).
Иерархия типов данных и переменных
Любая программа задает иерархическую систему типов данных, на основе которой определяются переменные. Наконец-то мы может соединить воедино все средства, предназначенные в Си для этих целей. Прежде всего, программа оперирует набором имен, которые обозначают типы данных, «источники» их появления в программе могут быть самыми разными:
· имена базовых типов данных заданы в трансляторе «от рождения»;
Кроме этих явно заданных имен в иерархии типов возможны неявно заданные промежуточные типы, которые вводятся вышеупомянутыми контекстными определениями. Если же тип данных упоминается сам по себе, безотносительно к какой-либо переменной, то это можно сделать с использованием абстрактного типа данных.
· в операторе создания динамических переменных new;
· в операции явного преобразования типа данных;
· при объявлении формальных параметров внешней функции с использованием прототипа.
Например, при резервировании памяти функцией нижнего уровня malloc для создания массива из 20 указателей необходимо знать размерность указателя char *, это можно сделать выражением, содержащим операцию sizeof для абстрактного типа данных char * — malloc (20* sizeof ( char *)).
typedef char *PSTR; // PSTR — имя производного типа данных – указатель на char или char *
PSTR p, q[20],*pp; // Эквивалентно char * p , * q [20], ** pp ;
char name[20]; // Элементы структуры
A , *B, X[10]; // переменных
Это определение создает систему явно поименованных и промежуточных типов, порождающих переменные.
рис.55.1. Иерархия типов данных и переменных
Функция как тип данных
В системе определения типов данных функция стоит особняком, все-таки она является алгоритмической компонентой. То, что функция рассматривается как тип данных, возможно потому, что она имеет результат – т.е. данные. Формально функция – это переменная производного типа данных по отношению к результату, который она дает. Иначе говоря, функция – это то, что можно вызвать, применив к ее имени операцию () справа . Еще одна возможность использовать функцию как переменную – получить указатель на нее (см. 9.3).
Указатель на массив
Поскольку любой указатель может ссылаться на массив, термин «указатель на массив» для Си – то же самое, что «масло масляное». Тем не менее, он имеет смысл, если речь идет об указателе на область памяти, содержащей двумерный массив (матрицу), а адресуемой единицей является одномерный массив (строка).
Для работы с многомерными массивами вводятся особые указатели -указатели на массивы. Они представляют собой обычные указатели, адресуемым элементом которых является не базовый тип, а массив элементов этого типа:
for (int j=0; (*p)[j]; j++) putchar((*p)[j]);
Вопросы без ответов
Определите вид объекта (переменная, функция), задаваемого в контекстном определении или объявлении, а также все неявно заданные типы данных. Найдите абстрактный тип данных и определите назначение.
Источник
Определение типа данных в ячейке или переменной
В языке VBA есть универсальные типы данных, т.е. способные хранить как число, так и строку, дату и любой другой тип информации. Например, ячейка в таблице может содержать что угодно и изначально, программа не знает какой в ней тип данных хранится. Кроме того, в самой программе может использоваться тип данных Variant, который так же может содержать любое значение любого типа.
Чтобы определить какой тип данных в ячейке или в переменной типа Variant, можно воспользоваться несколькими способами.
Способ 1. Использовать функцию TypeName для определения типа данных
Эта функция возвращает строку с названием типа данных на английском. В качестве аргумента принимает переменную, значение ячейки.
Обратите внимание: Функция определяет только стандартные типы данных и не может определить пользовательский тип (определенный с помощью Type).
Возможные возвращаемые функцией значения:
Byte | Число типа Byte |
Integer | Целое число |
Long | Длинное целое число |
Single | Число одиночной точности с плавающей запятой |
Double | Число двойной точности с плавающей запятой |
Currency | Валюта |
Decimal | Число с плавающей запятой |
Date | Дата |
String | Строка |
Boolean | Логическое |
Error | Ошибка |
Empty | Не проинициализировано (т.е. переменная не была объявлена) |
Null | Неверные данные (в переменной нет корректных данных) |
Object | Объект (класс) |
Unknown | Тип данных не известен |
Nothing | Объект, никуда не ссылающийся |
Приведу несколько примеров по использованию TypeName.
Пример 1. Определение типа переменной.
Обратите внимание: если вы используете результат TypeName в условии, т.е. проверяете, соответствует ли тип данных определенному, например, Integer, то регистр символов возвращаемого типа имеет значение. Т.е. нужно писать Integer с заглавной буквы, либо использовать приведение всех символов к одному регистру.
Пример 2. Использование TypeName в условии.
Пример 3. Определение типа данных в ячейке.
Если функции была передана переменная массив, она вернет тип данных в массиве с добавлением скобок.
Пример 4. Определение типа массива.
Способ 2. Проверка на возможность преобразования строки к нужному типу.
Бывает ситуация, когда значение, например, число или дата, содержится в строке. В этом случае TypeName вернет String, а не Integer или Date. Чтобы узнать, что содержится в строке, можно воспользоваться одной из функций IsNumeric, IsDate, IsObject, IsArray, IsNull, IsError.
IsNumeric | Проверяет может ли выражение быть преобразовано в число |
IsDate | Проверяет может ли выражение быть преобразовано в дату |
IsObject | Проверяет, является ли переменная объектом |
IsArray | Проверяет, является ли переменная массивом |
IsNull | Проверка на пустое значение |
IsError | Проверка выражения на ошибку |
Пример 4. Определение может ли переменная быть преобразована в число.
К сожалению, как видим из примера, нет возможности проверить, содержится ли в строке число с плавающей точкой.
Пример 5. Определение содержит ли переменная дату (может быть преобразована в дату).
Проверка, содержится ли число или дата в ячейке листа делается аналогично, как и с переменными.
Помимо этих способов можно конечно еще придумать и другие, например, проверку строки с данными регулярным выражением или пройти по каждому символу в цикле и проверить цифра это или нет и тому подобное. Но на мой взгляд, описанных мной способов вполне достаточно для решения повседневных задач.
Источник
Типы Данных И Их Объявление
Важное отличие языка СИ от других языков (PL1, FORTRAN, и др.) является отсутствие принципа умолчания, что приводит к необходимости объявления всех переменных используемых в программе явно вместе с указанием соответствующих им типов.
Объявления переменной имеет следующий формат:
Описатель — идентификатор простой переменной либо более сложная конструкция с квадратными скобками, круглыми скобками или звездочкой (набором звездочек).
Спецификатор типа — одно или несколько ключевых слов, определяющие тип объявляемой переменной. В языке СИ имеется стандартный набор типов данных, используя который можно сконструировать новые (уникальные) типы данных.
Инициатор — задает начальное значение или список начальных значений, которые (которое) присваивается переменной при объявлении.
Спецификатор класса памяти — определяется одним из четырех ключевых слов языка СИ: auto, extern, register, static, и указывает,каким образом будет распределяться память под объявляемую переменную, с одной стороны, а с другой, область видимости этой переменной, т.е., из каких частей программы можно к ней обратиться.
1.2.1 Категории типов данных
Ключевые слова для определения основных типов данных
Переменная любого типа может быть объявлена как немодифицируемая. Это достигается добавлением ключевого слова const к спецификатору-типа. Объекты с типом const представляют собой данные используемые только для чтения, т.е. этой переменной не может быть присвоено новое значение. Отметим, что если после слова const отсутствует спецификатор-типа, то подразумевается спецификатор типа int. Если ключевое слово const стоит перед объявлением составных типов (массив, структура, смесь, перечисление), то это приводит к тому, что каждый элемент также должен являться немодифицируемым, т.е. значение ему может быть присвоено только один раз.
Примеры объявления составных данных будут рассмотрены ниже.
1.2.2. Целый тип данных
Для определения данных целого типа используются различные ключевые слова, которые определяют диапазон значений и размер области памяти, выделяемой под переменные (табл. 6).
Тип | Размер памяти в байтах | Диапазон значений |
---|---|---|
char | 1 | от -128 до 127 |
int | Для IBM XT,AT,SX,DX 2 | |
short | 2 | от -32768 до 32767 |
long | 4 | от -2 147 483 648 до 2 147 483 647 |
unsigned shar | 1 | oт 0 до 255 |
unsigned int | Для IBM XT,AT,SX,DX 2 | |
unsigned short | 2 | от 0 до 65535 |
unsigned long | 4 | от 0 до 4 294 967 295 |
Отметим, что ключевые слова signed и unsigned необязательны. Они указывают, как интерпретируется нулевой бит объявляемой переменной, т.е., если указано ключевое слово unsigned, то нулевой бит интерпретируется как часть числа, в противном случае нулевой бит интерпретируется как знаковый. В случае отсутствия ключевого слова unsigned целая переменная считается знаковой. В том случае, если спецификатор типа состоит из ключевого типа signed или unsigned и далее следует идентификатор переменной, то она будет рассматриваться как переменная типа int. Например:
Отметим, что модификатор-типа char используется для представления символа (из массива представление символов) или для объявления строковых литералов. Значением объекта типа char является код (размером 1 байт), соответствующий представляемому символу. Для представления символов русского алфавита, модификатор типа идентификатора данных имеет вид unsigned char, так как коды русских букв превышают величину 127.
Следует сделать следующее замечание: в языке СИ не определено представление в памяти и диапазон значений для идентификаторов с модификаторами-типа int и unsigned int. Размер памяти для переменной с модификатором типа signed int определяется длиной машинного слова, которое имеет различный размер на разных машинах. Так, на 16-ти разрядных машинах размер слова равен 2-м байтам, на 32-х разрядных машинах соответственно 4-м байтам, т.е. тип int эквивалентен типам short int, или long int в зависимости от архитектуры используемой ПЭВМ. Таким образом, одна и та же программа может правильно работать на одном компьютере и неправильно на другом. Для определения длины памяти занимаемой переменной можно использовать операцию sizeof языка СИ, возвращающую значение длины указанного модификатора-типа.
Отметим также, что восьмеричные и шестнадцатеричные константы также могут иметь модификатор unsigned. Это достигается указанием префикса u или U после константы, константа без этого префикса считается знаковой.
1.2.3. Данные плавающего типа
Для переменных, представляющих число с плавающей точкой используются следующие модификаторы-типа : float, double, long double (в некоторых реализациях языка long double СИ отсутствует).
Величина с модификатором-типа float занимает 4 байта. Из них 1 байт отводится для знака, 8 бит для избыточной экспоненты и 23 бита для мантиссы. Отметим, что старший бит мантиссы всегда равен 1, поэтому он не заполняется, в связи с этим диапазон значений переменной с плавающей точкой приблизительно равен от 3.14E-38 до 3.14E+38.
Величина типа double занимает 8 бит в памяти. Ее формат аналогичен формату float. Биты памяти распределяются следующим образом: 1 бит для знака, 11 бит для экспоненты и 52 бита для мантиссы. С учетом опущенного старшего бита мантиссы диапазон значений равен от 1.7E-308 до 1.7E+308.
1.2.4. Указатели
Указатель — это адрес памяти, распределяемой для размещения идентификатора (в качестве идентификатора может выступать имя переменной, массива, структуры, строкового литерала). В том случае, если переменная объявлена как указатель, то она содержит адрес памяти, по которому может находится скалярная величина любого типа. При объявлении переменной типа указатель, необходимо определить тип объекта данных, адрес которых будет содержать переменная, и имя указателя с предшествующей звездочкой (или группой звездочек). Формат объявления указателя:
спецификатор-типа [ модификатор ] * описатель .
Спецификатор-типа задает тип объекта и может быть любого основного типа, типа структуры, смеси (об этом будет сказано ниже). Задавая вместо спецификатора-типа ключевое слово void, можно своеобразным образом отсрочить спецификацию типа, на который ссылается указатель. Переменная, объявляемая как указатель на тип void, может быть использована для ссылки на объект любого типа. Однако для того, чтобы можно было выполнить арифметические и логические операции над указателями или над объектами, на которые они указывают, необходимо при выполнении каждой операции явно определить тип объектов. Такие определения типов может быть выполнено с помощью операции приведения типов.
В качестве модификаторов при объявлении указателя могут выступать ключевые слова const, near, far, huge. Ключевое слово const указывает, что указатель не может быть изменен в программе. Размер переменной объявленной как указатель, зависит от архитектуры компьютера и от используемой модели памяти, для которой будет компилироваться программа. Указатели на различные типы данных не обязательно должны иметь одинаковую длину.
Для модификации размера указателя можно использовать ключевые слова near, far, huge.
1.2.5. Переменные перечислимого типа
Переменная, которая может принимать значение из некоторого списка значений, называется переменной перечислимого типа или перечислением.
Объявление перечисления начинается с ключевого слова enum и имеет два формата представления.
Формат 1. enum [имя-тега-перечисления] <список-перечисления>описатель[,описатель. ];
Формат 2. enum имя-тега-перечисления описатель [,описатель..];
Объявление перечисления задает тип переменной перечисления и определяет список именованных констант, называемый списком-перечисления. Значением каждого имени списка является некоторое целое число.
Переменная типа перечисления может принимать значения одной из именованных констант списка. Именованные константы списка имеют тип int. Таким образом, память соответствующая переменной перечисления, это память необходимая для размещения значения типа int.
Переменная типа enum могут использоваться в индексных выражениях и как операнды в арифметических операциях и в операциях отношения.
В первом формате 1 имена и значения перечисления задаются в списке перечислений. Необязательное имя-тега-перечисления, это идентификатор, который именует тег перечисления, определенный списком перечисления. Описатель именует переменную перечисления. В объявлении может быть задана более чем одна переменная типа перечисления.
Список-перечисления содержит одну или несколько конструкций вида:
идентификатор [= константное выражение]
Каждый идентификатор именует элемент перечисления. Все идентификаторы в списке enum должны быть уникальными. В случае отсутствия константного выражения первому идентификатору соответствует значение 0, следующему идентификатору — значение 1 и т.д. Имя константы перечисления эквивалентно ее значению.
Идентификатор, связанный с константным выражением, принимает значение, задаваемое этим константным выражением. Константное выражение должно иметь тип int и может быть как положительным, так и отрицательным. Следующему идентификатору в списке присваивается значение, равное константному выражению плюс 1, если этот идентификатор не имеет своего константного выражения. Использование элементов перечисления должно подчиняться следующим правилам:
1. Переменная может содержать повторяющиеся значения.
2. Идентификаторы в списке перечисления должны быть отличны от всех других идентификаторов в той же области видимости, включая имена обычных переменных и идентификаторы из других списков перечислений.
3. Имена типов перечислений должны быть отличны от других имен типов перечислений, структур и смесей в этой же области видимости.
4. Значение может следовать за последним элементом списка перечисления.
В данном примере объявлен перечислимый тег week, с соответствующим множеством значений, и объявлена переменная rab_ned имеющая тип week.
Во втором формате используется имя тега перечисления для ссылки на тип перечисления, определяемый где-то в другом месте. Имя тега перечисления должно относится к уже определенному тегу перечисления в пределах текущей области видимости. Так как тег перечисления объявлен где-то в другом месте, список перечисления не представлен в объявлении.
В объявлении указателя на тип данных перечисления и объявляемых typedef для типов перечисления можно использовать имя тега перечисления до того, как данный тег перечисления определен. Однако определение перечисления должно предшествовать любому действию используемого указателя на тип объявления typedef. Объявление без последующего списка описателей описывает тег, или, если так можно сказать, шаблон перечисления.
1.2.6. Массивы
Массивы — это группа элементов одинакового типа (double, float, int и т.п.). Из объявления массива компилятор должен получить информацию о типе элементов массива и их количестве. Объявление массива имеет два формата:
спецификатор-типа описатель [константное — выражение];
Описатель — это идентификатор массива .
Спецификатор-типа задает тип элементов объявляемого массива. Элементами массива не могут быть функции и элементы типа void.
Константное-выражение в квадратных скобках задает количество элементов массива. Константное-выражение при объявлении массива может быть опущено в следующих случаях:
— при объявлении массив инициализируется,
— массив объявлен как формальный параметр функции,
— массив объявлен как ссылка на массив, явно определенный в другом файле.
В языке СИ определены только одномерные массивы, но поскольку элементом массива может быть массив, можно определить и многомерные массивы. Они формализуются списком константных-выражений следующих за идентификатором массива, причем каждое константное-выражение заключается в свои квадратные скобки.
Каждое константное-выражение в квадратных скобках определяет число элементов по данному измерению массива, так что объявление двухмерного массива содержит два константных-выражения, трехмерного — три и т.д. Отметим, что в языке СИ первый элемент массива имеет индекс равный 0.
В последнем примере объявлен массив w[3][3]. Списки, выделенные в фигурные скобки, соответствуют строкам массива, в случае отсутствия скобок инициализация будет выполнена неправильно.
В языке СИ можно использовать сечения массива, как и в других языках высокого уровня (PL1 и т.п.), однако на использование сечений накладывается ряд ограничений. Сечения формируются вследствие опускания одной или нескольких пар квадратных скобок. Пары квадратных скобок можно отбрасывать только справа налево и строго последовательно. Сечения массивов используются при организации вычислительного процесса в функциях языка СИ, разрабатываемых пользователем.
Если при обращении к некоторой функции написать s[0], то будет передаваться нулевая строка массива s.
При обращении к массиву b можно написать, например, b[1][2] и будет передаваться вектор из четырех элементов, а обращение b[1] даст двухмерный массив размером 3 на 4. Нельзя написать b[2][4], подразумевая, что передаваться будет вектор, потому что это не соответствует ограничению наложенному на использование сечений массива.
Пример объявления символьного массива.
char str[] = «объявление символьного массива»;
Следует учитывать, что в символьном литерале находится на один элемент больше, так как последний из элементов является управляющей последовательностью ‘\0’.
1.2.7. Структуры
Cтруктуры — это составной объект, в который входят элементы любых типов, за исключением функций. В отличие от массива, который является однородным объектом, структура может быть неоднородной. Тип структуры определяется записью вида:
В структуре обязательно должен быть указан хотя бы один компонент. Определение структур имеет следующий вид:
где тип-данных указывает тип структуры для объектов, определяемых в описателях. В простейшей форме описатели представляют собой идентификаторы или массивы.
Переменные s1, s2 определяются как структуры, каждая из которых состоит из двух компонент х и у. Переменная sm определяется как массив из девяти структур. Каждая из двух переменных date1, date2 состоит из трех компонентов year, moth, day. >p>Существует и другой способ ассоциирования имени с типом структуры, он основан на использовании тега структуры. Тег структуры аналогичен тегу перечислимого типа. Тег структуры определяется следующим образом:
где тег является идентификатором.
В приведенном ниже примере идентификатор student описывается как тег структуры:
Тег структуры используется для последующего объявления структур данного вида в форме:
struct тег список-идентификаторов;
struct studeut st1,st2;
Использование тегов структуры необходимо для описания рекурсивных структур. Ниже рассматривается использование рекурсивных тегов структуры.
Тег структуры node действительно является рекурсивным, так как он используется в своем собственном описании, т.е. в формализации указателя next. Структуры не могут быть прямо рекурсивными, т.е. структура node не может содержать компоненту, являющуюся структурой node, но любая структура может иметь компоненту, являющуюся указателем на свой тип, как и сделано в приведенном примере.
Доступ к компонентам структуры осуществляется с помощью указания имени структуры и следующего через точку имени выделенного компонента, например:
1.2.8. Объединения (смеси)
Объединение подобно структуре, однако в каждый момент времени может использоваться (или другими словами быть ответным) только один из элементов объединения. Тип объединения может задаваться в следующем виде:
Главной особенностью объединения является то, что для каждого из объявленных элементов выделяется одна и та же область памяти, т.е. они перекрываются. Хотя доступ к этой области памяти возможен с использованием любого из элементов, элемент для этой цели должен выбираться так, чтобы полученный результат не был бессмысленным.
Доступ к элементам объединения осуществляется тем же способом, что и к структурам. Тег объединения может быть формализован точно так же, как и тег структуры.
Объединение применяется для следующих целей:
— инициализации используемого объекта памяти, если в каждый момент времени только один объект из многих является активным;
— интерпретации основного представления объекта одного типа, как если бы этому объекту был присвоен другой тип.
Память, которая соответствует переменной типа объединения, определяется величиной, необходимой для размещения наиболее длинного элемента объединения. Когда используется элемент меньшей длины, то переменная типа объединения может содержать неиспользуемую память. Все элементы объединения хранятся в одной и той же области памяти, начиная с одного адреса.
При использовании объекта infor типа union можно обрабатывать только тот элемент который получил значение, т.е. после присвоения значения элементу inform.fio, не имеет смысла обращаться к другим элементам. Объединение ua позволяет получить отдельный доступ к младшему ua.al[0] и к старшему ua.al[1] байтам двухбайтного числа ua.ax .
1.2.9. Поля битов
Элементом структуры может быть битовое поле, обеспечивающее доступ к отдельным битам памяти. Вне структур битовые поля объявлять нельзя. Нельзя также организовывать массивы битовых полей и нельзя применять к полям операцию определения адреса. В общем случае тип структуры с битовым полем задается в следующем виде:
длинна — поля задается целым выражением или константой. Эта константа определяет число битов, отведенное соответствующему полю. Поле нулевой длинны обозначает выравнивание на границу следующего слова.
Структуры битовых полей могут содержать и знаковые компоненты. Такие компоненты автоматически размещаются на соответствующих границах слов, при этом некоторые биты слов могут оставаться неиспользованными.
Ссылки на поле битов выполняются точно так же, как и компоненты общих структур. Само же битовое поле рассматривается как целое число, максимальное значение которого определяется длиной поля.
1.2.10. Переменные с изменяемой структурой
Очень часто некоторые объекты программы относятся к одному и тому же классу, отличаясь лишь некоторыми деталями. Рассмотрим, например, представление геометрических фигур. Общая информация о фигурах может включать такие элементы, как площадь, периметр. Однако соответствующая информация о геометрических размерах может оказаться различной в зависимости от их формы.
Рассмотрим пример, в котором информация о геометрических фигурах представляется на основе комбинированного использования структуры и объединения.
В общем случае каждый объект типа figure будет состоять из трех компонентов: area, perimetr, type. Компонент type называется меткой активного компонента, так как он используется для указания, какой из компонентов объединения geom_fig является активным в данный момент. Такая структура называется переменной структурой, потому что ее компоненты меняются в зависимости от значения метки активного компонента (значение type).
Отметим, что вместо компоненты type типа int, целесообразно было бы использовать перечисляемый тип. Например, такой
Константы CIRCLE, BOX, TRIANGLE получат значения соответственно равные 0, 1, 2. Переменная type может быть объявлена как имеющая перечислимый тип :
enum figure_chess type;
В этом случае компилятор СИ предупредит программиста о потенциально ошибочных присвоениях, таких, например, как
В общем случае переменная структуры будет состоять из трех частей: набор общих компонент, метки активного компонента и части с меняющимися компонентами. Общая форма переменной структуры, имеет следующий вид:
Пример определения переменной структуры с именем helth_record
Обращаться к компонентам структуры можно при помощи ссылок:
1.2.11. Определение объектов и типов
Как уже говорилось выше, все переменные используемые в программах на языке СИ, должны быть объявлены. Тип объявляемой переменной зависит от того, какое ключевое слово используется в качестве спецификатора типа и является ли описатель простым идентификатором или же комбинацией идентификатора с модификатором указателя (звездочка), массива (квадратные скобки) или функции (круглые скобки).
При объявлении простой переменной, структуры, смеси или объединения, а также перечисления, описатель — это простой идентификатор. Для объявления указателя, массива или функции идентификатор модифицируется соответствующим образом: звездочкой слева, квадратными или круглыми скобками справа.
Отметим важную особенность языка СИ, при объявлении можно использовать одновременно более одного модификатора, что дает возможность создавать множество различных сложных описателей типов.
Однако надо помнить, что некоторые комбинации модификаторов недопустимы:
— элементами массивов не могут быть функции,
— функции не могут возвращать массивы или функции.
При инициализации сложных описателей квадратные и круглые скобки (справа от идентификатора) имеют приоритет перед звездочкой (слева от идентификатора). Квадратные или круглые скобки имеют один и тот же приоритет и раскрываются слева направо. Спецификатор типа рассматривается на последнем шаге, когда описатель уже полностью проинтерпретирован. Можно использовать круглые скобки, чтобы поменять порядок интерпретации на необходимый.
Для интерпретации сложных описаний предлагается простое правило, которое звучит как «изнутри наружу», и состоит из четырех шагов.
1. Начать с идентификатора и посмотреть вправо, есть ли квадратные или круглые скобки.
2. Если они есть, то проинтерпретировать эту часть описателя и затем посмотреть налево в поиске звездочки.
3. Если на любой стадии справа встретится закрывающая круглая скобка, то вначале необходимо применить все эти правила внутри круглых скобок, а затем продолжить интерпретацию.
4. Интерпретировать спецификатор типа.
В данном примере объявляется переменная comp (1), как массив из десяти (2) указателей (3) на функции (4), возвращающие указатели (5) на целые значения (6).
Переменная var (1) объявлена как указатель (2) на функцию (3) возвращающую указатель (4) на массив (5) из 10 элементов, которые являются указателями (6) на значения типа char.
Кроме объявлений переменных различных типов, имеется возможность объявить типы. Это можно сделать двумя способами. Первый способ — указать имя тега при объявлении структуры, объединения или перечисления, а затем использовать это имя в объявлении переменных и функций в качестве ссылки на этот тег. Второй — использовать для объявления типа ключевое слово typedef.
При объявлении с ключевым словом typedef, идентификатор стоящий на месте описываемого объекта, является именем вводимого в рассмотрение типа данных, и далее этот тип может быть использован для объявления переменных.
Отметим, что любой тип может быть объявлен с использованием ключевого слова typedef, включая типы указателя, функции или массива. Имя с ключевым словом typedef для типов указателя, структуры, объединения может быть объявлено прежде чем эти типы будут определенны, но в пределах видимости объявителя.
При объявлении переменных и типов здесь были использованы имена типов (MATH FIO). Помимо этого, имена типов могут еще использоваться в трех случаях: в списке формальных параметров, в объявлении функций, в операциях приведения типов и в операции sizeof (операция приведения типа).
Именами типов для основных типов, типов перечисления, структуры и смеси являются спецификаторы типов для этих типов. Имена типов для типов указателя массива и функции задаются при помощи абстрактных описателей следующим образом:
Абстрактный-описатель — это описатель без идентификатора, состоящий из одного или более модификаторов указателя, массива или функции. Модификатор указателя (*) всегда задается перед идентификатором в описателе, а модификаторы массива [] и функции () — после него. Таким образом, чтобы правильно интерпретировать абстрактный описатель, нужно начать интерпретацию с подразумеваемого идентификатора.
Абстрактные описатели могут быть сложными. Скобки в сложных абстрактных описателе задают порядок интерпретации подобно тому, как это делалось при интерпретации сложных описателей в объявлениях.
1.2.12. Инициализация данных
При объявлении переменной ей можно присвоить начальное значение, присоединяя инициатор к описателю. Инициатор начинается со знака «=» и имеет следующие формы.
Формат 1: = инициатор;
Формат 1 используется при инициализации переменных основных типов и указателей, а формат 2 — при инициализации составных объектов.
Переменная tol инициализируется символом ‘N’.
const long megabute = (1024 * 1024);
Немодифицируемая переменная megabute инициализируется константным выражением после чего она не может быть изменена.
Инициализируется двухмерный массив b целых величин элементам массива присваиваются значения из списка. Эта же инициализация может быть выполнена следующим образом :
При инициализации массива можно опустить одну или несколько размерностей
Если при инициализации указано меньше значений для строк, то оставшиеся элементы инициализируются 0, т.е. при описании
элементы первой строки получат значения 1 и 2, а второй 3 и 0.
При инициализации составных объектов, нужно внимательно следить за использованием скобок и списков инициализаторов.
В данном примере инициализируется массив структур comp из двух строк и трех столбцов, где каждая структура состоит из двух элементов real и imag.
В этом примере компилятор интерпретирует рассматриваемые фигурные скобки следующим образом:
— первая левая фигурная скобка — начало составного инициатора для массива comp2;
— вторая левая фигурная скобка — начало инициализации первой строки массива comp2[0]. Значения 1,1 присваиваются двум элементам первой структуры;
— первая правая скобка (после 1) указывает компилятору, что список инициаторов для строки массива окончен, и элементы оставшихся структур в строке comp[0] автоматически инициализируются нулем;
— аналогично список <2,3>инициализирует первую структуру в строке comp[1], а оставшиеся структуры массива обращаются в нули;
— на следующий список инициализаторов <4,5>компилятор будет сообщать о возможной ошибке так как строка 3 в массиве comp2 отсутствует.
При инициализации объединения задается значение первого элемента объединения в соответствии с его типом.
Инициализируется переменная pers.name, и так как это массив, для его инициализации требуется список значений в фигурных скобках. Первые пять элементов массива инициализируются значениями из списка, остальные нулями.
Инициализацию массива символов можно выполнить путем использования строкового литерала.
char stroka[ ] = «привет»;
Инициализируется массив символов из 7 элементов, последним элементом (седьмым) будет символ ‘\0’, которым завершаются все строковые литералы.
В том случае, если задается размер массива, а строковый литерал длиннее, чем размер массива, то лишние символы отбрасываются.
Следующее объявление инициализирует переменную stroka как массив, состоящий из семи элементов.
char stroka[5] = «привет»;
В переменную stroka попадают первые пять элементов литерала, а символы ‘Т’ и ‘\0’ отбрасываются.
Если строка короче, чем размер массива, то оставшиеся элементы массива заполняются нулями.
Отметим, что инициализация переменной типа tab может иметь следующий вид:
union tab pers1 = «Антон»;
и, таким образом, в символьный массив попадут символы:
а остальные элементы будут инициализированы нулем.
Источник