Главная страница
Навигация по странице:

  • 9. ПРИЛОЖЕНИЕ А: СПРАВОЧНОЕ РУКОВОДСТВО ПО ЯЗЫКУ ‘C’ 9.1. Введение

  • 10. Лексические соглашения

  • 10.1. Комментарии Комментарий открывается символами /* и заканчивается символами /*.Комментарии не вкладываются друг в друга.10.2. Идентификаторы (имена)

  • 10.4.2. Явные длинные константы

  • 10.4.3. Символьные константы

  • 10.4.4. Плавающие константы

  • 10.6. Характеристики аппаратных средств

  • 11. Синтаксическая нотация

  • 12. Что в имене тебе моем

  • Язык С (Керниган, Ричи). Язык сиБ. В. Керниган, Д. М. Ричи


    Скачать 1.46 Mb.
    НазваниеЯзык сиБ. В. Керниган, Д. М. Ричи
    АнкорЯзык С (Керниган, Ричи).pdf
    Дата23.04.2018
    Размер1.46 Mb.
    Формат файлаpdf
    Имя файлаЯзык С (Керниган, Ричи).pdf
    ТипДокументы
    #18413
    страница18 из 23
    1   ...   15   16   17   18   19   20   21   22   23
    8.7. Пример - распределитель памяти.
    В главе 5 мы написали бесхитростный вариант функции ALLOC. Вариант,
    который мы напишем теперь, не содержит ограничений: обращения к функциям
    ALLOC и FREE могут перемежаться в любом порядке; когда это необходимо,
    функция ALLOC обращается к операционной системе за дополнительной памятью.
    Кроме того, что эти процедуры полезны сами по себе, они также иллюстрируют некоторые соображения, связанные с написанием машинно-зависимых программ относительно машинно-независимым образом, и показывают практическое применение структур, объединений и конструкций TYPEDEF.
    Вместо того, чтобы выделять память из скомпилированного внутри массива фиксированного размера, функция ALLOC будет по мере необходимости обращаться за памятью к операционной системе. Поскольку различные события в программе могут требовать асинхронного выделения памяти, то память,
    управляемая ALLOC, не может быть непрерывной. В силу этого свободная па- мять хранится в виде цепочки свободных блоков. Каждый блок включает размер,
    указатель следующего блока и саму свободную память. Блоки упорядочиваются в порядке возрастания адресов памяти, причем последний блок (с наибольшим адресом) указывает на первый, так что цепочка фактически оказывается кольцом.
    При поступлении запроса список свободных блоков просматривается до тех пор, пока не будет найден достаточно большой блок. Если этот блок имеет в точности требуемый размер, то он отцепляется от списка и передается пользователю. Если же этот блок слишком велик, то он разделяется, нужное количество передается пользователю, а остаток возвращается в свободный список. Если достаточно большого блока найти не удается, то операционной системой выделяется новый блок, который включается в список свободных блоков; затем поиск возобновляется.
    Освобождение памяти также влечет за собой просмотр свободного списка в поиске подходящего места для введения освобожденного блока. Если этот освободившийся блок с какой-либо стороны примыкает к блоку из списка свободных блоков, то они объединяются в один блок большего размера, так что память не становится слишком раздробленной. Обнаружить смежные блоки просто, потому что свободный список содержится в порядке возрастания адресов.
    Одна из проблем, о которой мы упоминали в главе 5, заключается в обеспечении того, чтобы возвращаемая функцией ALLOC память была выровнена подходящим образом для тех объектов, которые будут в ней храниться. Хотя машины и различаются, для каждой машины существует тип, требующий наибольших ограничений по размещению памяти, если данные самого ограничительного типа можно поместить в некоторый определенный адрес, то это же возможно и для всех остальных типов.
    Например, на IBM 360/370,HONEYWELL 6000 и многих других машинах любой объект может храниться в границах, соответствующим переменным типа DOUBLE; на PDP-11 будут достаточны переменные типа INT.
    Свободный блок содержит указатель следующего блока в цепочке, запись

    180
    «Язык С» Б.В. Керниган, Д.М. Ричи
    о размере блока и само свободное пространство; управляющая информация в начале называется заголовком. Для упрощения выравнивания все блоки кратны размеру заголовка, а сам заголовок выровнен надлежащим образом. Это достигается с помощью объединения, которое содержит желаемую структуру заголовка и образец наиболее ограничительного по выравниванию типа:
    TYPEDEF INT ALIGN; /*FORCES ALIGNMENT ON PDP-11*/
    UNION HEADER \( /*FREE BLOCK HEADER*/
    STRUCT \(
    UNION HEADER *PTR; /*NEXT FREE BLOCK*/
    UNSIGNED SIZE; /*SIZE OF THIS FREE BLOCK*/
    \) S;
    ALIGN X; /*FORCE ALIGNMENT OF BLOCKS*/ \);
    TYPEDEF UNION HEADER HEADER;
    Функция ALLOC округляет требуемый размер в символах до нужного числа единиц размера заголовка; фактический блок, который будет выделен, содержит на одну единицу больше, предназначаемую для самого заголовка, и это и есть значение, которое записывается в поле SIZE заголовка. Указатель, возвращаемый функцией ALLOC, указывает на свободное пространство, а не на сам заголовок.
    STATIC HEADER BASE; /*EMPTY LIST TO GET STARTED*/
    STATIC HEADER *ALLOCP=NULL; /*LAST ALLOCATED BLOCK*/
    CHAR *ALLOC(NBYTES)/*GENERAL-PURPOSE STORAGE ALLOCATOR*/
    UNSIGNED NBYTES;
    \(
    HEADER *MORECORE();
    REGISTER HEADER *P, *G;
    REGISTER INT NUNITS;
    NUNITS=1+(NBYTES+SIZEOF(HEADER)-1)/SIZEOF(HEADER);
    IF ((G=ALLOCP)==NULL) \( /*NO FREE LIST YET*/
    BASE.S PTR=ALLOCP=G=&BASE;
    BASE.S.SIZE=0;
    \)
    FOR (P=G>S.PTR; ; G=P, P=P->S.PTR) \(
    IF (P->S.SIZE>=NUNITS) \( /*BIG ENOUGH*/
    IF (P->S.SIZE==NUNITS) /*EXACTLY*/
    G->S.PTR=P->S.PTR;
    ELSE \( /*ALLOCATE TAIL END*/
    P->S.SIZE-=NUNITS;
    P+=P->S.SIZE;
    P->S.SIZE=NUNITS;
    \)
    ALLOCP=G;
    RETURN((CHAR *)(P+1));

    «Язык С» Б.В. Керниган, Д.М. Ричи
    181
    \)
    IF(P==ALLOCP) /*WRAPPED AROUND FREE LIST*/
    IF((P=MORECORE(NUNITS))==NULL)
    RETURN(NULL); /*NONE LEFT*/
    \)
    \)
    Переменная BASE используется для начала работы. Если ALLOCP имеет значение NULL, как в случае первого обращения к ALLOC, то создается вырожденный свободный список: он состоит из свободного блока размера нуль и указателя на самого себя. В любом случае затем исследуется свободный список. Поиск свободного блока подходящего размера начинается с того места
    (ALLOCP), где был найден последний блок; такая стратегия помогает сохранить однородность диска. Если найден слишком большой блок, то пользователю предлагается его хвостовая часть; это приводит к тому, что в заголовке исходного блока нужно изменить только его размер. Во всех случаях возвращае- мый пользователю указатель указывает на действительно свободную область,
    лежащую на единицу дальше заголовка. Обратите внимание на то, что функция
    ALLOC перед возвращением “P” преобразует его в указатель на символы.
    Функция MORECORE получает память от операционной системы. Детали того, как это осуществляется, меняются, конечно, от системы к системе. На системе UNIX точка входа SBRK(N) возвращает указатель на “N”
    дополнительных байтов памяти.(указатель удволетворяет всем ограничениям на выравнивание). Так как запрос к системе на выделение памяти является сравнительно дорогой операцией, мы не хотим делать это при каждом обращении к функции ALLOC. Поэтому функция MORECORE округляет затребованное число единиц до большего значения; этот больший блок будет затем разделен так, как необходимо. Масштабирующая величина является параметром, который может быть подобран в соответствии с необходимостью.
    #DEFINE NALLOC 128 /*#UNITS TO ALLOCATE AT ONCE*/
    STATIC HEADER *MORECORE(NU) /*ASK SYSTEM FOR MEMORY*/
    UNSIGNED NU;
    \(
    CHAR *SBRK();
    REGISTER CHAR *CP;
    REGISTER HEADER *UP;
    REGISTER INT RNU;
    RNU=NALLOC*((NU+NALLOC-1)/NALLOC);
    CP=SBRK(RNU*SIZEOF(HEADER));
    IF ((INT)CP==-1) /*NO SPACE AT ALL*/
    RETURN(NULL);
    UP=(HEADER *)CP;
    UP->S.SIZE=RNU;
    FREE((CHAR *)(UP+1));

    182
    «Язык С» Б.В. Керниган, Д.М. Ричи
    RETURN(ALLOCP);
    \)
    Если больше не осталось свободного пространства, то функция SBRK
    возвращает “-1”, хотя NULL был бы лучшим выбором. Для надежности сравнения “-1” должна быть преобразована к типу INT. Снова приходится многократно использовать явные преобразования (перевод) типов, чтобы обеспечить определенную независимость функций от деталей представления указателей на различных машинах.
    И последнее - сама функция FREE. Начиная с ALLOCP, она просто просматривает свободный список в поиске места для введения свободного блока. Это место находится либо между двумя существующими блоками,
    либо в одном из концов списка. В любом случае, если освободившийся блок примыкает к одному из соседних, смежные блоки объединяются. Следить нужно только затем, чтобы указатели указывали на то, что нужно, и чтобы размеры были установлены правильно.
    FREE(AP) /*PUT BLOCKE AP IN FREE LIST*/
    CHAR *AP;
    \(
    REGISTER HEADER *P, *G;
    P=(HEADER*)AP-1; /*POINT TO HEADER*/
    FOR (G=ALLOCP; !(P>G && P>G->S.PTR);G=G->S.PTR)
    IF (G>=G->S.PTR && (P>G \!\! PS.PTR))
    BREAK; /*AT ONE END OR OTHER*/
    IF (P+P->S.SIZE==G->S.PTR)\(/*JOIN TO UPPER NBR*/
    P->S.SIZE += G->S.PTR->S.SIZE;
    P->S.PTR = G->S.PTR->S.PTR;
    \) ELSE
    P->S.PTR = G->S.PTR;
    IF (G+G->S.SIZE==P) \( /*JOIN TO LOWER NBR*/
    G->S.SIZE+=P->S.SIZE;
    G->S.PTR=P->S.PTR;
    \) ELSE
    G->S.PTR=P;
    ALLOCP = G;
    \)
    Хотя распределение памяти по своей сути зависит от используемой машины, приведенная выше программа показывает, как эту зависимость можно регулировать и ограничить весьма небольшой частью программы.
    Использование TYPEDEF и UNION позволяет справиться с выравниванием
    (при условии, что функция SBRK обеспечивает подходящий указатель).
    Переводы типов организуют выполнение явного преобразования типов и даже справляются с неудачно разработанным системным интерфейсом. И хотя

    «Язык С» Б.В. Керниган, Д.М. Ричи
    183
    рассмотренные здесь подробности связаны с распределением памяти, общий подход равным образом применим и к другим ситуациям.
    Упражнение 8-6.
    Функция из стандартной библиотеки CALLOC(N,SIZE) возвращает указатель на “N” объектов размера SIZE, причем соответствующая память инициализируется на нуль. напишите программу для CALLOC, используя функцию ALLOC либо в качестве образца, либо как функцию, к которой происходит обращение.
    Упражнение 8-7.
    Функция ALLOC принимает затребованный размер, не проверяя его правдоподобности; функция FREE полагает, что тот блок, который она должна освободить, содержит правильное значение в поле размера.
    Усовершенствуйте эти процедуры, затратив больше усилий на проверку ошибок.
    Упражнение 8-8.
    Напишите функцию BFREE(P,N), которая включает произвольный блок
    “P” из “N” символов в список свободных блоков, управляемый функциями
    ALLOC и FREE. С помощью функции BFREE пользователь может в любое время добавлять в свободный список статический или внешний массив.

    184
    «Язык С» Б.В. Керниган, Д.М. Ричи
    9. ПРИЛОЖЕНИЕ А:
    СПРАВОЧНОЕ РУКОВОДСТВО ПО ЯЗЫКУ ‘C’
    9.1. Введение
    Это руководство описывает язык ‘с’ для компьютеров DEC PDP-11,
    HONEYWELL 6000, IBM система/370 и INTERDATA 8/32. там, где есть расхождения, мы сосредотачиваемся на версии для PDP-11, стремясь в то же время указать детали, которые зависят от реализации. За малым исключением, эти расхождения непосредственно обусловлены основными свойствами используемого аппаратного оборудования; различные компиляторы обычно вполне совместимы.
    10. Лексические соглашения
    Имеется шесть классов лексем: идентификаторы, ключевые слова,
    константы, строки, операции и другие разделители. Пробелы, табуляции ,
    новые строки и комментарии (совместно, “пустые промежутки”), как описано ниже, игнорируются, за исключением тех случаев, когда они служат разделителями лексем. Необходим какой-то пустой промежуток для разделения идентификаторов, ключевых слов и констант, которые в против- ном случае сольются.
    Если сделан разбор входного потока на лексемы вплоть до данного символа, то в качестве следующей лексемы берется самая длинная строка символов, которая еще может представлять собой лексему.
    10.1. Комментарии
    Комментарий открывается символами /* и заканчивается символами /*.
    Комментарии не вкладываются друг в друга.
    10.2. Идентификаторы (имена)
    Идентификатор - это последовательность букв и цифр; первый символ должен быть буквой. Подчеркивание _ считается буквой. Буквы нижнего и верхнего регистров различаются. значащими являются не более, чем первые восемь символов, хотя можно использовать и больше. На внешние идентификаторы, которые используются различными ассемблерами и загрузчиками, накладыватся более жесткие ограничения:
    DEC PDP-11 7 символов, 2 регистра
    HONEYWELL 6000 6 символов, 1 регистр
    IBM 360/370 7 символов, 1 регистр
    INTERDATA 8/32 8 символов, 2 регистра

    «Язык С» Б.В. Керниган, Д.М. Ричи
    185
    10.3. Ключевые слова
    Следующие идентификаторы зарезервированы для использования в качестве ключевых слов и не могут использоваться иным образом:
    INT
    EXTERN
    ELSE
    CHAR
    REGISTER
    FOR
    FLOAT
    TYPEDEF
    DO
    DOUBLE
    STATIC
    WHILE
    STRUCT
    GOTO
    SWITCH
    UNION
    RETURN
    CASE
    LONG
    SIZEOF
    DEFAULT
    SHORT
    BREAK
    ENTRY
    UNSIGNED
    CONTINUE
    *AUTO
    IF
    Ключевое слово ENTRY в настоящее время не используется каким-либо компилятором; оно зарезервировано для использования в будущем. В
    некоторых реализациях резервируется также слова FORTRAN и ASM
    10.4. Константы
    Имеется несколько видов констант, которые перечислены ниже. В пункте
    10.6 резюмируются характеристики аппаратных средств, которые влияют на размеры.
    10.4.1. Целые константы
    Целая константа, состоящая из последовательности цифр, считается восьмеричной, если она начинается с 0 (цифра нуль), и десятичной в противном случае. Цифры 8 и 9 имеют восьмеричные значения 10 и 11
    соответственно. Последовательность цифр, которой предшествуют символы
    0х (нуль, х-маленькое) или 0х (нуль х-большое), рассматривается как шестнадцатиричное целое. Шестнадцатиричные цифры включают буквы от а (маленькое) или а (большое) до F (маленькое) или F (большое) со значениями от 10 до 15. Десятичная константа, величина которой превышает наибольшее машинное целое со знаком, считается длинной; восмеричная или шестнадцатиричная константа, которое превышает наибольшее машинное целое без знака, также считается длинной.
    10.4.2. Явные длинные константы
    Десятичная, восмеричная или шестнадцатиричная константа, за которой непосредственно следует L (эль-маленькое) или L (эль-большое), является длинной константой. Как обсуждается ниже, на некоторых машинах целые и длинные значения могут рассматриваться как идентичные.

    186
    «Язык С» Б.В. Керниган, Д.М. Ричи
    10.4.3. Символьные константы
    Символьная константа - это символ, заключенный в одиночные кавычки,
    как, например, ‘X’. Значением символьной константы является численное значение этого символа в машинном представлении набора символов.
    Некоторые неграфические символы, одиночная кавычка ‘ и обратная косая черта \ могут быть представлены в соответствии со следующей таблицей условных последовательностей:
    новая строка
    NL/LF/
    \N
    горизонтальная табуляция
    HT
    \T
    символ возврата на одну позицию
    BS
    \B
    возврат каретки
    CR
    \R
    переход на новую страницу
    FF
    \F
    обратная косая черта
    \
    \\
    одиночная кавычка

    \’
    комбинация битов
    DDD
    \DDD
    Условная последовательность \DDD состоит из обратной косой черты, за которой следуют 1,2 или 3 восмеричных цифры, которые рассмативаются как задающие значение желаемого символа. Специальным случаем этой конструкции является последовательность \0 (за нулем не следует цифра), которая опреде- ляет символ NUL. если следующий за обратной косой чертой символ не совпадает с одним из указанных, то обратная косая черта игнорируется.
    10.4.4. Плавающие константы
    Плавающая константа состоит из целой части, десятичной точки, дробной части, буквы E (маленькая) или E (большая) и целой экспоненты с необязательным знаком. Как целая, так и дробная часть являются последовательностью цифр. Либо целая, либо дробная часть (но не обе) может отсутствовать; либо десятичная точка,
    либо е (маленькая) и экспонента (но не то и другое одновременно) может отсут- ствовать. Каждая плавающая константа считается имеющей двойную точность.
    10.5. Строки
    Строка - это последовательность символов, заключенная в двойные кавычки, как, наприимер,”...”. Строка имеет тип “массив массивов” и класс памяти STATIC (см. Пункт 4 ниже). Строка инициализирована указанными в ней символами. Все строки, даже идентично записанные, считаются различными. Компилятор помещает в конец каждой строки нулевой байт \0,
    с тем чтобы просматривающая строку программа могла определить ее конец.
    Перед стоящим внутри строки символом двойной кавычки “ должен быть поставлен символ обратной косой черты \; кроме того, могут использоваться те же условия последовательности, что и в символьных константах. И
    последнее, обратная косая черта \, за которой непосредственно следует символ новой строки, игнорируется.

    «Язык С» Б.В. Керниган, Д.М. Ричи
    187
    10.6. Характеристики аппаратных средств
    Следующая ниже таблица суммирует некоторые свойства аппаратного оборудования, которые меняются от машины к машине. Хотя они и влияют на переносимость программ, на практике они представляют маленькую проблему, чем это может казаться заранее.
    Таблица 1
    11. Синтаксическая нотация
    В используемой в этом руководстве синтаксической нотации синтаксические категории выделяются курсивом (прим. перев.: в настоящее время синтексические категории вместо курсивом выделяются подчеркиванием), а литерные слова и символы - жирным шрифтом. Альтернативные категории перечисляются на отдельных строчках. Необязательный символ, терминальный или нетерминальный, указывается индексом “необ”, так что
    \( выражение
    ———— необ \)
    указывает на необязательное выражение, заключенное в фигурных скобках. Синтаксис суммируется в пункте 18.
    12. Что в имене тебе моем?
    Язык “C” основывает интерпретацию идентификатора на двух признаках идентификатора: его классе памяти и его типе. Класс памяти определяет место и время хранения памяти, связанной с идентификатором; тип определяет смысл величин, находящихся в памяти, определенной под идентификатором.
    Имеются четыре класса памяти: автоматическая, статическая, внешняя и регистровая. Автоматические переменные являются локальными для каждого вызова блока и исчезают при выходе из этого блока. Статические переменные являются локальными, но сохраняют свои значения для следующего входа в блок даже после того, как управление передается за пределы блока. Внешние переменные существуют и сохраняют свои значения в течение выполнения всей программы и могут использоваться для связи между функциями, в том числе и между независимо скомпилированными функциями. Регистровые
    DEC PDP-11
    ASCII
    CHAR 8 BITS
    INT 16
    SHORT 16
    LONG 32
    FLOAT 32
    DOUBLE 64
    RANGE -38/+38
    HONEYWELL
    ASCII
    9 BITS
    36 36 36 36 72 38/+38
    IBM 370
    EBCDIC
    8 BITS
    32 16 32 32 64
    -76/+76
    INTERDATA
    ASCII
    8 BITS
    32 16 32 32 64 -76/+76 8/32

    188
    «Язык С» Б.В. Керниган, Д.М. Ричи
    переменные хранятся (ели это возможно) в быстрых регистрах машины;
    подобно автоматическим переменным они являются локальными для каждого блока и исчезают при выходе из этого блока.
    В языке “C” предусмотрено несколько основных типов объектов:
    объекты, написанные как символы (CHAR), достаточно велики, чтобы хранить любой член из соответствующего данной реализации внутреннего набора символов, и если действительный символ из этого набора символов хранится в символьной переменной, то ее значение эквивалентно целому коду этого символа. В символьных переменных можно хранить и другие величины, но реализация будет машинно-зависимой.
    Можно использовать до трех размеров целых, описываемых как SHORT
    INT, INT и LONG INT. Длинные целые занимают не меньше памяти, чем короткие, но в конкретной реализации может оказаться, что либо короткие целые, либо длинные целые, либо те и другие будут эквивалентны простым целым. “Простые” целые имеют естественный размер, предусматриваемый архиитектурой используемой машины; другие размеры вводятся для удво- летворения специальных потребностей.
    Целые без знака, описываемые как UNSIGNED, подчиняются законам арифметики по модулю 2**N, где N - число битов в их представлении. (На
    PDP-11 длинные величины без знака не предусмотрены).
    Плавающие одинарной точности (FLOAT) и плавающие двойной точности
    (DOUBLE) в некоторых реализациях могут быть синонимами.
    Поскольку объекты упомянутых выше типов могут быть разумно интерпретированы как числа, эти типы будут называться арифметическими.
    типы CHAR и INT всех размеров совместно будут называться целочисленными. Типы FLOAT и DOUBLE совместно будут называться плавающими типами.
    Кроме основных арифметических типов существует концептуально бесконечный класс производных типов, которые образуются из основных типов следующим образом:
    массивы объектов большинства типов;
    функции, которые возвращают объекты заданного типа;
    указатели на объекты данного типа;
    структуры, содержащие последовательность объектов различных типов;
    объединения, способные содержать один из нескольких объектов различных типов.
    Вообще говоря, эти методы построения объектов могут применяться рекурсивно.
    13. Объекты и L-значения
    Объект является доступным обработке участком памяти; L-значение - это выражение, ссылающееся на объект. Очевидным примером выражения L- значения является идентификатор. Существуют операции, результатом

    «Язык С» Б.В. Керниган, Д.М. Ричи
    189
    которых являются L-значения; если, например, E - выражение указанного типа, то *E является выражением L-значения, ссылающимся на объект E.
    Название “L-значение” происходит от выражения присваивания E1=E2, в котором левая часть должна быть выражением L-значения. При последующем обсуждении каждой операции будет указываться, ожидает ли она операндов
    L-значения и выдает ли она L-значение.
    1   ...   15   16   17   18   19   20   21   22   23


    написать администратору сайта