- •Введение
- •Соглашения о нотации
- •Часть 1 описание языка си элементы языка си
- •Алфавит
- •Буквы и цифры
- •Пробельные символы
- •Разделители
- •Специальные символы
- •Операции
- •Константы
- •Целые константы
- •Константы с плавающей точкой
- •Символьные константы
- •Символьные строки
- •Идентификаторы
- •Ключевые слова
- •Комментарии
- •Структура программы Исходная программа
- •Исходные файлы
- •Выполнение программы
- •Время жизни и область действия
- •Пространства имен
- •Объявления
- •Базовые типы данных
- •Спецификации типов и их сокращения
- •Области значений
- •Размер памяти и область значений типов
- •Описатели Синтаксис описателей
- •Интерпретация составных описателей
- •Описатели с модификаторами
- •Интерпретация описателей с модификаторами
- •Модификаторы const и volatile
- •Модификаторы cdecl и pascal
- •Модификатор pascal
- •Модификаторы near, far, huge
- •Модификатор interrupt
- •Объявление переменных
- •Объявление простой переменной
- •Объявление переменной перечислимого типа
- •Объявление структуры
- •Битовые поля
- •Объявление объединения
- •Объявление массива
- •Объявление указателя
- •Объявление функции (прототип)
- •Список типов аргументов
- •Классы памяти
- •Объявление переменной на внешнем уровне
- •Объявление переменной на внутреннем уровне
- •Инициализация
- •Базовые типы и указатели
- •Составные типы
- •Строковые инициализаторы
- •Объявление типа
- •Объявление тега
- •Объявление typedef
- •Абстрактные имена типов
- •Выражения Введение
- •Операнды
- •Идентификаторы
- •Константы
- •Символьные строки
- •Вызовы функций
- •Индексные выражения
- •Доступ к многомерному массиву
- •Выбор элемента
- •Операции и l-выражения
- •Скобочные выражения
- •Константные выражения
- •Операции
- •Преобразования по умолчанию
- •Унарные операции Унарный минус (-)
- •Логическое отрицание (!)
- •Адресация "&"
- •Косвенная адресация "*"
- •Операция sizeof
- •Мультипликативные операции
- •Умножение (*)
- •Деление (/)
- •Остаток от деления (%)
- •Аддитивные операции
- •Вычитание (-)
- •Адресная арифметика
- •Операции сдвига
- •Операции отношения
- •Поразрядные операции
- •Логические операции
- •Логическое и (&&)
- •Логическое или (||)
- •Операция последовательного вычисления
- •Условная операция
- •Операции присваивания
- •Операции инкремента и декремента
- •Простое присваивание
- •Составное присваивание
- •Приоритет и порядок выполнения
- •Приоритет и ассоциативность операций в языке Си
- •Побочные эффекты
- •Преобразования типов
- •Преобразования типов при присваивании
- •Преобразование знаковых целых типов
- •Преобразование беззнаковых целых типов
- •Преобразование беззнаковых целых типов
- •Преобразование указателей
- •Преобразования других типов
- •Явные преобразования типов
- •Преобразования типов при вызовах функций
- •Операторы Введение
- •Пустой оператор
- •Составной оператор
- •Оператор-выражение
- •Условный оператор if
- •Вложенность
- •Оператор пошагового цикла for
- •Оператор цикла с предусловием while
- •Оператор цикла с постусловием do
- •Оператор продолжения continue
- •Оператор-переключатель switch
- •Оператор разрыва break
- •Оператор перехода goto
- •Оператор возврата return
- •Функции Введение
- •Определение функции
- •Класс памяти
- •Модификаторы типа функции
- •Типы возвращаемых значений
- •Формальные параметры
- •Тело функции
- •Объявление функции
- •Вызов функции
- •Фактические аргументы
- •Вызов функции с переменным числом аргументов
- •Рекурсивные вызовы
- •Директивы препроцессора и указания компилятору Введение
- •Именованные константы и макроопределения
- •Директива #define
- •Склейка лексем и преобразование аргументов макроопределений
- •Директива #undef
- •Включение файлов
- •Условная компиляция
- •Директивы #if, #elif, #else, #endif
- •Директивы #ifdef и #ifndef
- •Управление нумерацией строк
- •Директива обработки ошибок
- •Пустая директива
- •Указания компилятору языка Си
- •Псевдопеременные
- •Модели памяти
- •Виды моделей
- •Малая модель
- •Средняя модель
- •Компактная модель
- •Большая модель
- •Максимальная модель
- •Модификация стандартной модели памяти
- •Объявление данных
- •Объявление функций
- •Модели памяти сп тс
- •Часть II
- •Краткое описание библиотеки
- •Работа с областями памяти и строками
- •Определение класса символов и преобразование символов
- •Форматные преобразования данных
- •Работа с каталогами файловой системы
- •Операции над файлами
- •Ввод и вывод
- •Функции вода/вывода высокого уровня
- •Высокоуровневое открытие файлов
- •Стандартные потоки: stdin, stdout, stdeir, stdaux, stdprn.
- •Управление буферизацией потоков
- •Закрытие потоков
- •Чтение и запись данных
- •Обнаружение ошибок
- •Функции вода/вывода нижнего уровня
- •Открытие файлов
- •9.6.2.2. Переопределение дескрипторов (handle)
- •Чтение и запись данных
- •Закрытие файлов
- •Функции вода/вывода с консольного терминала и порта
- •Математические функции
- •Динамическое распределение памяти
- •Использование системных вызовов операционной системы ms-dos
- •Управление процессами
- •Поиск и сортировка
- •Функции работы со временем
- •Функции работы со списком аргументов
- •Другие функции
Базовые типы данных
В языке Си реализован набор типов данных, называемых "базовыми" типами. Спецификации этих типов перечислены в таблице 3.1.
Таблица 3.1.
Тип long float реализован только в версии 4.0 СП MSC и эквивалентен типу double . В версии 5.0 СП MSC и в СП ТС реализован тип long double , причем в версии 5.0 СП MSC и версии 1.5 СП ТС он эквивалентен типу double , а в версии 2.0 СП ТС является самостоятельным типом размером 80 битов.
Типы char , int , short и long имеют две формы — знаковую (signed ) и беззнаковую (unsigned ). В совокупности они образуют целый тип. Перечислимый тип также служит для представления целых значений, однако, переменная перечислимого типа может принимать значения только из набора, заданного в ее объявлении. Спецификации типов float и double относятся к плавающему типу.
Целый тип (включая перечислимый тип) и плавающий тип в совокупности образуют арифметический тип.
Тип void (пустой) имеет специальное назначение. Указание спецификации типа void в объявлении функции означает, что функция не возвращает значений. Указание типа void в списке объявлений аргументов в объявлении функции означает, что функция не принимает аргументов. Можно объявить указатель на тип void ; он будет указывать на любой, т.е. неспецифицированный тип. Тип void может быть указан в операции приведения типа. Приведение значения выражения к типу void явно указывает на то, что это значение не используется. Нельзя объявить переменную типа void .
При записи спецификаций целого и плавающего типа допустимы сокращения, приведенные в таблице 3.2. Например, в целых типах ключевое слово signed может быть опущено. Если ключевое слово unsigned отсутствует в записи спецификации типа short , int или long , то тип целого будет знаковым, даже если опущено ключевое слово signed .
По умолчанию тип char всегда имеет знак. Однако существует опция компилятора языка Си, позволяющая изменить умолчание для char со знакового типа на беззнаковый. Если эта опция задана, то сокращение char имеет тот же смысл, что и unsigned char , и, следовательно, для объявления символьной переменной со знаком должно быть записано ключевое слово signed .
Таблица 3.2.
Спецификации типов и их сокращения
Примечание. В данной книге в основном используются сокращенные формы записи спецификаций типов, перечисленные в таблице 3.2; при этом предполагается, что тип char по умолчанию имеет знак.
Области значений
Область значений — это интервал от минимального до максимального значения, которое может быть представлено в переменной данного типа. В таблице 3.3 приведен размер занимаемой памяти и области значений переменных для каждого типа. Поскольку переменных типа void не существует, он не включен в эту таблицу.
Таблица 3.3.
Размер памяти и область значений типов
Тип char может использоваться для хранения буквы, цифры или другого символа из множества представимых символов. Значением объекта типа char является код, соответствующий данному символу. Тип char интерпретируется как однобайтовое целое с областью значений от -128 до 127. Тип unsigned char может содержать значения в интервале от 0 до 255. В частности, буквы русского алфавита имеют коды, соответствующие типу unsigned char .
Следует отметить, что представление в памяти и область значений для типов int и unsigned int не определены в языке Си. В большинстве систем программирования размер типа int (со знаком или без знака) соответствует реальному размеру целого машинного слова. Например, на 16-разрядном компьютере тип int занимает 16 разрядов, или 2 байта. На 32-разрядном компьютере тип int занимает 32 разряда, или 4 байта. Таким образом, тип int эквивалентен либо типу short int (короткое целое), либо типу long int (длинное целое), в зависимости от компьютера. Аналогично, тип unsigned int эквивалентен либо типу unsigned short int , либо типу unsigned long int . Однако рассматриваемые в данной книге компиляторы языка Си, разработанные для моделей IBM PC с 16-разрядным машинным словом, при работе на IBM PC/AT с процессором Intel 80386 (имеющим 32-разрядное машинное слово) отводят для типа int и unsigned int только 16 разрядов.
Спецификации типов int и unsigned int широко используются в программах на Си, поскольку они позволяют наиболее эффективно работать с целыми значениями на данном компьютере. Однако, поскольку размер типов int и unsigned int является машинно-зависимым, программы, зависящие от конкретного размера типа int или unsigned int на каком-либо компьютере, могут быть непереносимы на другой компьютер. Переносимость программ можно повысить, если использовать для ссылки на размер типа данных операцию sizeof .
Порядок размещения байтов в памяти для базовых целых типов следующий (по возрастанию адресов):
для типа short — b0, b1;
для типа long — b0, b1, b2, b3,
где b0—младший байт.
Архитектура процессора Intel 8086/88 позволяет размещать переменные различного размера в памяти, как с четного, так и с нечетного адреса. Однако в последнем случае обращение к переменным будет более медленным. В СП TC существует опция компиляции, задающая выравнивание всех объектов, занимающих более одного байта, на границу четного адреса. Память при этом будет использоваться менее эффективно, но скорость обращения к переменным возрастет. В СП MSC по умолчанию производится выравнивание на границу четного адреса. В версии 5.0 СП MSC существует опция компиляции, обеспечивающая выравнивание на границу, заданную программистом. Вопросы выравнивания структур рассматриваются в разделе 3.4.3.
Согласно правилам преобразования типов в языке Си (см. раздел 5 "Выражения"), не всегда возможно использовать в выражении максимальное или минимальное значение для константы данного типа.
Допустим, требуется использовать в выражении значение -32768 типа short . Константное выражение -32768 состоит из арифметической операции отрицания (-), предшествующей значению константы 32768. Поскольку значение 32768 слишком велико для типа short , компилятор языка Си представляет его типом long и, следовательно, константа -32768 будет иметь тип long . Значение -32768 может быть представлено типом short только путем явного приведения его к типу short с помощью выражения (short ) (‑32768). Информация при этом не будет потеряна, поскольку значение -32768 может быть представлено двумя байтами памяти.
Восьмеричные и шестнадцатеричные константы могут иметь знаковый или беззнаковый тип, в зависимости от их значения (см. раздел 1.2.1). Однако метод присвоения компилятором языка Си типов восьмеричным и шестнадцатеричным константам гарантирует, что в выражениях они будут вести себя как беззнаковые целые (поскольку их знаковый бит всегда равен нулю).
СП ТС позволяет явно присваивать константам беззнаковый тип с помощью суффикса u .
Для представления значений с плавающей точкой используется стандартный формат IEEE (Institute of Electrical and Electronics Engineers, Inc.). Значения типа float занимают 4 байта, состоящих из бита знака, 7-битовой двоичной экспоненты и 24-битовой мантиссы. Мантисса представляет число в интервале от 1.0 до 2.0. Поскольку старший бит мантиссы всегда равен единице, он не хранится в памяти. Это представление дает область значений приблизительно от 3.4Е-38 до 3.4Е+38.
Значения типа double занимают 8 байтов. Их формат аналогичен формату float , за исключением того, что экспонента занимает 11 битов, а мантисса 52 бита плюс неявный старший бит, единичный. Это дает область значений приблизительно от 1.7Е-308 до 1.7Е+308.
Значения типа long double занимают 80 битов; их область значений—от 3.4Е-4932 до 1.1Е+4932. Формат их аналогичен формату double , однако, мантисса длиннее на 16 битов.