
- •Язык программирования си для персонального компьютера введение
- •Часть 1 описание языка си
- •Элементы языка си
- •Алфавит
- •Буквы и цифры
- •Пробельные символы
- •Разделители
- •Специальные символы
- •Операции
- •Константы
- •Целые константы
- •Константы с плавающей точкой
- •Символьные константы
- •Символьные строки
- •Идентификаторы
- •Ключевые слова
- •Комментарии
- •Структура программы
- •Исходная программа
- •Исходные файлы
- •Выполнение программы
- •Время жизни и область действия
- •Области значений
- •Описатели
- •Синтаксис описателей
- •Интерпретация составных описателей
- •Описатели с модификаторами
- •Интерпретация описателей с модификаторами
- •Модификаторы const и volatile
- •Модификаторы cdecl и pascal
- •Модификаторы near, far, huge
- •Модификатор interrupt
- •Объявление переменных
- •Объявление простой переменной
- •Объявление переменной перечислимого типа
- •Объявление структуры
- •Объявление объединения
- •Объявление массива
- •Объявление указателя
- •Объявление функции (прототип)
- •Классы памяти
- •Объявление переменной на внешнем уровне
- •Объявление переменной на внутреннем уровне
- •Инициализация
- •Базовые типы и указатели
- •Составные типы
- •Строковые инициализаторы
- •Объявление типа
- •Объявление тега
- •Объявление typedef
- •Абстрактные имена типов
- •Выражения
- •Введение
- •Операнды
- •Идентификаторы
- •Константы
- •Символьные строки
- •Вызовы функций
- •Индексные выражения
- •Выбор элемента
- •Операции и l-выражения
- •Скобочные выражения
- •Константные выражения
- •Операции
- •Преобразования по умолчанию
- •Унарные операции
- •Мультипликативные операции
- •Аддитивные операции
- •Адресная арифметика
- •Операции сдвига
- •Операции отношения
- •Поразрядные операции
- •Логические операции
- •Операция последовательного вычисления
- •Условная операция
- •Операции присваивания
- •Операции инкремента и декремента
- •Простое присваивание
- •Составное присваивание
- •Приоритет и порядок выполнения
- •Приоритет и ассоциативность операций в языке Си
- •Побочные эффекты
- •Преобразования типов
- •Преобразования типов при присваивании
- •Преобразование знаковых целых типов
- •Явные преобразования типов
- •Преобразования типов при вызовах функций
- •Операторы
- •Введение
- •Пустой оператор
- •Составной оператор
- •Оператор-выражение
- •Условный оператор if
- •Оператор пошагового цикла for
- •Оператор цикла с предусловием while
- •Оператор цикла с постусловием do
- •Оператор продолжения continue
- •Оператор-переключатель switch
- •Оператор разрыва break
- •Оператор перехода goto
- •Оператор возврата return
- •Функции
- •Введение
- •Определение функции
- •Класс памяти
- •Модификаторы типа функции
- •Типы возвращаемых значений
- •Формальные параметры
- •Тело функции
- •Объявление функции
- •Вызов функции
- •Фактические аргументы
- •Вызов функции с переменным числом аргументов
- •Рекурсивные вызовы
- •Директивы препроцессора и указания компилятору
- •Введение
- •Именованные константы и макроопределения
- •Директива #define
- •Склейка лексем и преобразование аргументов макроопределений
- •Директива #undef
- •Включение файлов
- •Модели памяти
- •Виды моделей
- •Модификация стандартной модели памяти
- •Объявление данных
- •Объявление функций
- •Модели памяти сп тс
- •Основы доказательства правильности.
Модификация стандартной модели памяти
Работая в некоторой стандартной модели памяти, программист может в той или иной мере модифицировать ее, применяя в объявлениях модификаторы near, far и huge. Правила интерпретации объявлений с модификаторами рассмотрены в разделе 3.3.3.4 "Модификаторы near, far, huge".
Объявление данных
Если непосредственно за ключевым словом near, far или huge следует идентификатор, то это значит, что соответствующий элемент данных будет размещен в стандартном сегменте (для near) или может быть размещен в другом сегменте данных (для far или huge). Например, объявление
char far х;
сообщает, что адрес объекта х имеет тип far.
Если же непосредственно за ключевым словом near, far или huge следует признак указателя (звездочка), то это значит, что соответствующий указатель будет хранить адрес типа near, типа far или типа huge, соответственно. Например, объявление
char far *р;
сообщает, что указатель р имеет тип far, т. е. может указывать на объект, расположенный в любом сегменте данных (при этом тип адреса этого объекта должен быть far). Объявление
char * far р;
объявляет р как указатель на char, причем сам указатель р может находиться в любом сегменте, и его адрес имеет тип far. Объявление
char far * far р;
сообщает, что указатель р может указывать на объекты с адресом типа far. Адрес самого указателя р также имеет тип far.
Примеры:
char а[3000]; /* пример 1: малая модель */
char far b[30000]; /* пример 2: малая модель */
char a[3000]; /* пример 3: большая модель */
char near b[3000]; /* пример 4: большая модель */
char huge a[70000]; /* пример 5: малая модель */
char huge *pa; /* пример 6: малая модель */
char *pa; /* пример 7: малая модель */
char far *pb; /* пример 8: малая модель */
char far **pa; /* пример 9: малая модель */
char far **pa; /* пример 10: большая модель */
char far *near *pb; /* пример 11: любая модель */
char far *far *pb; /* пример 12: любая модель */
В примере 1 массиву а выделяется память в стандартном сегменте данных; массиву b во втором примере память может быть выделена в любом из сегментов данных программы. Поскольку оба объявления сделаны в малой модели, то, вероятно, массив а содержит часто используемые данные, которые для ускорения доступа должны располагаться в стандартном сегменте, а массив b содержит редко используемые данные, которые могут выйти за пределы 64-Кбайтного сегмента данных. Можно было бы использовать здесь другую модель памяти, в которой адрес данных по умолчанию имел бы тип far, однако для сохранения быстрого доступа к массиву а лучше сохранить малую модель, а адрес массива b объявить как far.
В примере 2 указан большой размер массива b, поскольку более вероятно, что программист будет модифицировать тип адреса объекта большой длины, который может не поместиться в текущий сегмент.
В примере 3, очевидно, скорость доступа к массиву а не является критичной; независимо от того, попадет он в стандартный сегмент или не попадет, обращение к нему всегда будет осуществляться по 32-битовому адресу. В примере 4 массиву b с помощью модификатора near явно назначен стандартный сегмент, с целью ускорения доступа к нему в большой модели.
В примере 5 массив а должен быть явно объявлен как huge, поскольку его размер превышает 64 Кбайта. Использование модификатора huge вместо выбора максимальной модели памяти в качестве стандартной позволяет сэкономить время доступа: только к массиву а обращение будет осуществляться по адресу типа huge, а все остальные данные будут размещаться в стандартном сегменте. Для обращения к массиву а может быть использован указатель ра из примера 6. Все арифметические операции над указателем ра (например, ра++) будут выполняться над всеми 32 его битами.
В примере 7 ра объявляется как указатель на near char. Указатель получает тип near по умолчанию, поскольку речь идет о малой модели. В примере 8 pb явно объявляется как указатель на far char. Он может быть использован, в частности, для доступа к символьному массиву, расположенному не в стандартном сегменте памяти. Например, ра может указывать на массив а из примера 1, а pb — на массив b из примера 2.
Хотя объявления ра в примерах 9 и 10 идентичны, в примере 9 ра объявляется как указатель на near массив указателей на тип far char, а в примере 10 ра объявляется как указатель на far массив указателей на тип far char.
В примере 11 pb объявляется как указатель на near массив указателей на тип far char. В примере 12 pb объявляется как указатель на far массив указателей на тип far char. В этих примерах употребление слов far и near изменяет действующие по умолчанию соглашения, связанные с моделями памяти; в отличие от примеров 9 и 10, объявления pb не зависят от выбранной модели памяти и в любой модели имеют одинаковый смысл.