ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



 

Часть 8

 
 
 
 
 
 
 
 
 
 
 
                   Матемтатическое обеспечение
                        персональных ЭВМ
 
 
 
                             TURBO-C
 
 
                         Описание языка
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                           Москва 1988
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                              - 2 -
 
 
 
 
 
 
 
 
                            Аннотация
 
 
 
      В данном документе приведены отличия языка Turbo-C от опи-
 сания языка в книге Б.Керниган, Д.Ритчи "Язык  программирования
 Си", М. "Финансы и статистика", 1985. Приведены расширения язы-
 ка. Авторы: Кашкарова В.А., Артамоненкова Н.Н.
 
 П_р_и_м_е_ч_а_н_и_е. Сокращения в тексте K&R означают ссылку на
 книгу   Б.Керниган,  Д.Ритчи  "Язык  программирования  Си",  М.
 "Финансы и статистика", 1985.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                              - 3 -
 
 
 
 
 
 
 
 
                           Содержание
 
 
    Аннотация................................................. 2
 
 1. ОТЛИЧИЯ Turbo-C от K&R.................................... 5
 
 1.1.  Комментарии (K&R 2.1).................................. 5
 1.2.  Идентификаторы (K&R 2.2)............................... 5
 1.3.  Ключевые слова (K&R 2.3)............................... 5
 1.4.  Константы (K&R 2.4).................................... 6
 1.4.1.  Целые константы (K&R 2.4.1).......................... 6
 1.4.2.  Символьные константы (K&R 2.4.3)..................... 7
 1.4.3.  Константы с плавающей точкой (K&R 2.4.4)............. 7
 1.5.  Строки (K&R 2.5)....................................... 8
 1.6.  Зависимость от машины (K&R 2.6)........................ 8
 1.7.  Преобразования (K&R 6)................................. 9
 1.7.1.  Char, int и enum (K&R 6.1)........................... 9
 1.7.2.  Указатели (K&R 6.4).................................. 9
 1.7.3.  Арифметические преобразования (K&R 6.6).............. 9
 1.8.  Операторы (K&R 7.2)....................................10
 1.9.  Спецификации типов (K&R 8.2)...........................10
 1.9.1.  Тип enum.............................................11
 1.9.2.  Тип void.............................................11
 1.9.3.  Знаковый модификатор.................................12
 1.9.4.  Модификатор const....................................12
 1.9.5.  Модификатор volatile.................................13
 1.9.6.  Модификаторы cdecl и pascal..........................13
 1.9.6.1.  pascal.............................................14
 1.9.6.2.  cdecl..............................................14
 1.9.7.  Модификаторы near, far и huge........................14
 1.10. Структуры и объединения (K&R 8.5)......................15
 1.10.1. Выравнивание слов....................................16
 1.10.2. Битовые поля.........................................16
 1.11. Операторы (K&R 9)......................................17
 1.12. Определение внешних функций (K&R 10.1).................17
 1.12.1. Модификаторы типа функции (K&R 10.1.1)...............17
 1.12.1.1. Модификатор функции pascal.........................17
 1.12.1.2. Модификатор функции cdecl..........................18
 1.12.1.3. Модификатор функции interrupt......................18
 1.12.1.4. Прототипы функций (K&R 10.1.2).....................19
 1.13. Правила видимости (K&R 11).............................23
 1.14. Команды управления трансляцией (R&K 12)................23
 1.14.1. Замена лексем (K&R 12.1).............................23
 1.14.2. Включение файла (K&R 12.2)...........................24
 1.14.3. Условная компиляция (K&R 12.3).......................25
 1.14.4. Управление строками (K&R 12.4).......................26
 1.14.5. Директива обработки ошибок (ANSI C 3.8.5)............26
 1.14.6. Директива PRAGMA (ANSI C 3.8.6)......................26
 1.14.6.1. #pragma inline.....................................27
 
                              - 4 -
 
 
 
 
 1.14.6.2. #pragma warn.......................................27
 1.14.7. Нулевая директива (ANSI C 3.7).......................27
 1.14.8. Встроенные макро-имена...............................28
 1.14.9. Встроенные макросы Turbo-C...........................28
 
 2. Модели памяти Turbo-C.....................................30
 
 2.1.     Использование    смешанных    моделей    памяти:
       модификаторы адресации.................................30
 
 3. Использование различных языков программирования...........32
 
 3.1.  Смешение языков программирования: интерфейс............32
 3.1.1.   Последовательности  передачи  параметров:  C   и
         Паскаль..............................................32
 3.1.1.1.    C-последовательность   передачи    параметров
           (соглашение вызова)................................32
 3.1.1.2.    Паскалевская   последовательность    передачи
           параметров (соглашение вызова).....................33
 3.1.2.  Интерфейс с ассемблером..............................35
 3.1.2.1.  Обращения к файлам .ASM из Turbo-C.................35
 3.1.2.2.  Определение констант и переменных..................36
 3.1.2.3.     Определение     глобальных     и     внешних
           идентификаторов....................................37
 3.1.3.  Обращения к Turbo-C из файла .ASM....................37
 3.1.3.1.  Ссылка на функции..................................37
 3.1.3.2.  Ссылка на данные...................................38
 3.1.4.  Встроенный ассемблер.................................38
 3.1.4.1.  Ссылки  на  данные  и  функции  из  встроенного
           ассемблера.........................................40
 3.1.4.2.  Использование структур.............................40
 3.1.4.3.  Использование команд перехода и меток..............41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                              - 5 -
 
 
 
 
                    1. ОТЛИЧИЯ Turbo-C от K&R
 
 
 
 
 
      Turbo-C поддерживает не только определения, данные в  K&R,
 но и большинство расширений ANSI-стандарта.  В  данном  разделе
 приведены дополнения к K&R; ссылки даны на соответствующие раз-
 делы приложения "Справочное руководство по языку C".
 
 
      1.1. Комментарии (K&R 2.1)
 
 
      Допускаются вложенные комментарии. В этом случае программа
 должна компилироваться с флагом -C. Для обеспечения мобильности
 удобнее отмечать код, который должен быть закомментирован,  ди-
 рективами #if 0 и #endif.
 
 
      1.2. Идентификаторы (K&R 2.2)
 
 
      В идентификаторах допускается знак $. Однако идентификатор
 может начинаться только с буквы или символа (_). Значащими  яв-
 ляются первые 32 символа идентификатора.  Для  изменения  числа
 значащих символов можно использовать при компиляции опцию -i#.
 
      32 символа являются значащими и для глобальных идентифика-
 торов, берущихся из других модулей.
 
 
      1.3. Ключевые слова (K&R 2.3)
 
 
      Ниже приведены ключевые слова,  зарезервированные  Turbo-C
 (TC) и расширениями ANSI-стандарта (AN). Данные слова не  могут
 быть использованы в  качестве  имен  идентификаторов.  Ключевые
 слова entry и fortran, упомянутые в K&R, не используются в Tur-
 bo-C.
 
         TC      asm             TC  _cs         TC  _DH
         TC      cdecl           TC  _ds         TC  _DL
         AN      const           TC  _es         TC  _DX
         AN      enum            TC  _ss         TC  _BP
         TC      far             TC  _AH         TC  _DI
         TC      huge            TC  _AL         TC  _SI
         TC      interrupt       TC  _AX         TC  _SP
         TC      near            TC  _BH
         TC      pascal          TC  _BL
         AN      signed          TC  _CH
         AN      void            TC  _CL
         AN      volatile        TC  _CX
 
                              - 6 -
 
 
 
 
      1.4. Константы (K&R 2.4)
 
 
      Turbo-C поддерживает все  типы  констант,  определенные  в
 K&R, с некоторыми расширениями.
 
 
      1.4.1. Целые константы (K&R 2.4.1)
 
 
      Д   Допускаются   десятичные   константы    в    диапазоне
 0...4294967295. (Отрицательные  константы  рассматриваются  как
 беззнаковые, к которым применен унарный оператор "минус".
 
      Суффикс U (или u), означает что константа имеет тип unsig-
 ned. Константа будет иметь тип unsigned long, если ее  значение
 будет превышать 65535, независимо от используемого основания.
 
 П_р_и_м_е_ч_а_н_и_е. Можно использовать как L, так и U суффиксы
 для одной и той же константы.
 
 
                                                       Таблица 1
 
              Целые константы Turbo-C (без L или U)
 
 ------------------------------------------------------
         Диапазон                Тип
 ------------------------------------------------------
         ________десятичные_константы_________
 0-32767                         int
 32767-2147483647                long
 2147483648-4294967295           unsigned long
 >4294967295                 будет переполнение
                             без предупреждения;
                             в результат будут
                             записаны младшие биты
                             действительного результата
         ________восьмеричные_константы________
 00-077777                       int
 0100000-0177777                 unsigned int
 01000000-017777777777           long
 010000000000-0377777777777      unsigned long
 >0377777777777              будет переполнение
      ________шестнадцатеричные_константы_________
 0x0000-0x7FFF                   int
 0x8000-0xFFFF                   unsigned int
 0x10000-0x7FFFFFFF              long
 0x80000000-0xFFFFFFFF           unsigned long
 >0xFFFFFFFF                 будет переполнение
 
 
 
 
 
                              - 7 -
 
 
 
 
      1.4.2. Символьные константы (K&R 2.4.3)
 
 
      Все константы  представляются  16-битовой  величиной  типа
 int.
 
      Turbo-C поддерживает ANSI-расширение, допускающее шестнад-
 цатеричное представление кодов символов. Например,  '\x1F'  или
 '\x82'.
 
      Кроме того, поддерживается другое ANSI-расширение,  допус-
 кающее ESC-последовательности. Данный список ESC-последователь-
 ностей представляет собой  дополнение  списка,  приведенного  в
 K&R.
 
 
                                                       Таблица 2
 
                 ESC-последовательности Turbo-C
 
 ------------------------------------------------------
 Последовательность  Код    Символ    Примечание
 ------------------------------------------------------
 \a                  0x07   BEL       Гудок
 \v                  0x0B   VT        Вертикальная
                                        табуляция
 \"                  0x22   "         Двойная кавычка
 \?                  0x3F   ?
 \DDD                       любой    тоже, что /ddd в K&R
 \xHHH               0xHHH  любой    HHH=1,2 или 3
                                    щестнадцатеричные
                                         цифры
 
 П_р_и_м_е_ч_а_н_и_е.   Т.к.  Turbo-C  допускает  двухсимвольные
 константы, может возникнуть двусмысленность, если  восьмеричная
 ESC-последовательность меньше чем  из  трех  цифр  предшествует
 цифре. В таких случаях, Turbo-C будет предполагать, что следую-
 щий символ - часть ESC-последовательности, даже если символ  не
 допускается для данного типа чисел.  Например,  константа  \258
 будет интерпретироваться как двухсимвольная константа,  состоя-
 щая из символов \25 и 8.
 
 
      1.4.3. Константы с плавающей точкой (K&R 2.4.4)
 
 
      Все константы, определенные как double, представляют собой
 константы с плавающей точкой.  Однако,  константа  с  плавающей
 точкой может иметь тип float; необходимо  добавлять  суффикс  F
 или f к ее значению.
 
 
 
 
 
                              - 8 -
 
 
 
 
      1.5. Строки (K&R 2.5)
 
 
      Turbo-C допускает  многостроковые  элементы  в  символьных
 константах; строковая константа будет представлять собой  объе-
 динение элементов.
 
      Например,
 
 main()
 {
      char *p;
      p="Данная программа - пример того, как Turbo-C"
        "будет автоматически\nосуществлять объединение"
        "строк в очень длинную строку;\n"
        "такая структура используется для большей"
        "наглядности программы.\n"
 }
 
 
      1.6. Зависимость от машины (K&R 2.6)
 
 
 
                                                       Таблица 3
 
            Список различных типов данных для Turbo-C
 
 ------------------------------------------------------
 Тип             Размер(в битах)        Диапазон
 ------------------------------------------------------
 unsigned char           8               0-255
 char                    8               -128-127
 enum                    16              -32768-32767
 unsigned short          16              0-65535
 short                   16              -32768-32767
 unsigned int            16              0-65535
 int                     16              -32768-32767
 unsigned long           32              0-4294967295
 
 long                    32      -2147483648-2147483647
 
 float                   32             3.4E-38-3.4E+38
 double                  64           1.7E-308-1.7E+308
 long double             64           1.7E-308-1.7E+308
 
 pointer                 16       (near, _cs, _ds, _ss)
 pointer                 32              (far, huge)
 
 П_р_и_м_е_ч_а_н_и_е. Тип long double допускается, но рассматри-
 вается как double.
 
 
 
 
                              - 9 -
 
 
 
 
      1.7. Преобразования (K&R 6)
 
 
 
      1.7.1. Char, int и enum (K&R 6.1)
 
 
      Преобразование символьной константы к целому имеет резуль-
 татом 16-битовое значение. Преобразование  символьного  объекта
 (переменной) к целочисленному объекту имеет результатом автома-
 тическое знаковое раширение, если вы сделали по  умолчанию  тип
 char беззнаковым (используя при компиляции опцию  -K).  Объекты
 типа signed char всегда используют знаковое расширение; объекты
 типа unsigned char всегда устанавливают  старший  бит  в  нуль,
 когда преобразуются в int.
 
      Значения типа enum преобразуются в  int  без  модификации;
 аналогично тип int преобразуется в перечислимый тип.
 
 
      1.7.2. Указатели (K&R 6.4)
 
 
      Указатели, используемые программой, могут  быть  различных
 размеров,   в  зависимости  от  используемой   модели   памяти.
 Например, когда вы компилируете программу, используя  специаль-
 ную модель памяти, адресуемые модификаторы (индексные регистры)
 (near, huge, far, _cs, _ds, _ss, _es)  могут  не  принимать  во
 внимание размер указателя, заданный данной моделью памяти.
 
      Указатель должен быть объявлен как указатель на  некоторый
 специальный тип, даже если данный тип - void (который в  дейст-
 вительности  означает  указатель  на  ничего).  Однако,  будучи
 объявлен, указатель может указывать на  объект  любого  другого
 типа. Turbo-C позволяет переназначать указатели, но  компилятор
 будет предупреждать, что произошло переназначение  указателя  -
 если указатель не был первоначально определен как указатель  на
 тип void. Однако указатели на типы данных не могут быть  преоб-
 разованы к указателям на типы функций, и наоборот.
 
 
      1.7.3. Арифметические преобразования (K&R 6.6)
 
 
        Преобразование  операндов  в  арифметических  выражениях
 выполняется по следующим правилам:
 
 1)     Любой не-integer и не-double тип преобразуется как пока-
        зано в таблице, приведенной ниже.
 
 2)     Если какой-либо из операндов имеет  тип  double,  другой
        операнд тоже преобразуется в double.
 
 
 
                             - 10 -
 
 
 
 
 3)     Если какой-либо из операндов имеет  тип  unsigned  long,
        другой операнд тоже преобразуется в unsigned long.
 
 4)     Если какой-либо из операндов имеет тип unsigned,  другой
        операнд тоже преобразуется в unsigned.
 
 
                                                       Таблица 4
 
              Методы арифметических преобразований
 
 ------------------------------------------------------
                   Результат
 Тип           преобразования          Метод
 ------------------------------------------------------
 char               int              знаковый
 unsigned char      int         нулевой старший байт
                                         (всегда)
 signed char        int         знаковый (всегда)
 short              int         если беззнаковый,
                                 то беззнаковый int
 enum               int         та же величина
 float              double      мантисса дополняется 0
 
 
      1.8. Операторы (K&R 7.2)
 
 
      Turbo-C поддерживает унарный оператор  +.  Обычно  Turbo-C
 осуществляет перегруппировку выражений, переупорядочивая комму-
 тативные операторы (такие как * и двоичный +), пытаясь  создать
 выражения эффективные при компиляции. Однако Turbo-C  не  будет
 переорганизовывать выражения с унарным оператором  +.  Следова-
 тельно, вы можете контролировать вычисления с плавающей точкой,
 т.е. отлавливать  ошибки  точности  и  переполнения,  используя
 унарный оператор +, и при этом не разбивая целое  выражение  на
 отдельные выражения. Например, Если a,  b,  c  и  f  имеют  тип
 float, выражение
 
      f=a++(b+c)
 
 будет вычисляться следующим образом: результат (b+c) будет при-
 бавлен к a.
 
 
      1.9. Спецификации типов (K&R 8.2)
 
 
      Turbo-C поддерживает следующие основные типы, не указанные
 в K&R.
 
      - unsigned char
 
      - unsigned short
 
                             - 11 -
 
 
 
 
      - unsigned long
 
      - long double
 
      - enumeration
 
      - viod
 
      Тип long double эквивалентен типу double.
 
 
      1.9.1. Тип enum
 
 
      Turbo-C поддерживает все перечислимые типы ANSI-стандарта.
 Перечислимый тип данных используется  для  описания  дискретной
 последовательности целых значений. Например,
 
      enum days { sun, mon, tues, wed, thur, fri, sat};
 
      Имена, занесенные в days, представляют собой  целые  конс-
 танты, первая (sun) автоматически установлена в нуль  и  каждая
 следующая имеет значение  на  единицу  больше,  чем  предыдущая
 (mon=1, tues=2 и т.д.). Можно присвоить константам определенные
 значения; имена, не имеющие определенных значений, будут, как и
 раньше, иметь значения предыдущих костант, увеличенные на  еди-
 ницу. Например,
 
      enum coins {penny=1, nickle=5, dime=10, quarter=25};
 
      Переменной перечислимого типа может быть присвоено  значе-
 ние любого типа int - проверка типа не производится.
 
 
      1.9.2. Тип void
 
 
      Turbo-C поддерживает тип void, определенный  в  ANSI-стан-
 дарте. Данный тип используется для явного описания функций,  не
 возвращающих значений. Аналогично, пустой список параметров мо-
 жет быть объявлен словом void. Например,
 
 void putmsg(void)
 {
         printf("Hello, world\n");
 }
 
 main()
 {
         putmsg();
 }
 
      Можно преобразовывать выражение  к  типу  void,  для  того
 чтобы явно указать, что значение, возвращаемое функцией,  игно-
 
                             - 12 -
 
 
 
 
 рируется. Например, если  вы  хотите  приостановить  выполнение
 программы до тех пор пока  пользователь  не  нажмет  какую-либо
 клавишу, вы можете написать:
 
         (void) getch();
 
      Кроме того, можно объявить указатель на объект типа  void.
 Данный указатель не будет указателем на ничего; создастся  ука-
 затель на какой-то объект данных, тип которого нет необходимос-
 ти определять. Вы можете присваивать любой указатель  указателю
 типа void, и обратно. Однако вы не можете использовать оператор
 косвенной адресации (*), т.к. используемый тип неопределен.
 
 
      1.9.3. Знаковый модификатор
 
 
      Кроме указанных в K&R трех  типов  модификаторов  -  long,
 short и unsigned - Turbo-C поддерживает еще три: signed,  const
 и vilatile (ANSI-стандарт).
 
      Модификатор signed явно указывает, что величина со знаком.
 Данный модификатор используется преимущественно для  документи-
 рованности и завершенности программ. Однако, если  вы  компили-
 руете программу, используя по умолчанию  беззнаковый  тип  char
 (вместо знакового), необходимо использовать модификатор signed,
 для того чтобы определить переменную или  функцию  типа  signed
 char. Модификатор signed, использованный сам по себе,  означает
 signed int, также как unsigned означает unsigned int.
 
 
      1.9.4. Модификатор const
 
 
      Модификатор const, как определено в ANSI-стандарте, не до-
 пускает каких бы то ни было переопределений значения  константы
 или других косвенных действий, таких как уменьшение или  увели-
 чение. Указатель на тип const не может быть изменен, в  отличии
 от самого объекта, который он определяет.
 
 П_р_и_м_е_ч_а_н_и_е. Модификатор const, используемый сам по се-
 бе, эквивалентен const int. Рассмотрим следующий примеры:
 
         const float pi          =3.1415926;
         const       maxint      =32767;
         const *char str         ="Hello, world";
 
      Приведенные ниже утверждения недопустимы:
 
         pi  = 3.0;              /* Присвоение значения
                                         константе */
         i   = maxint--;         /* Уменьшение константы */
         str = "Hi, there!";     /* Переназначение указателя */
 
 
                             - 13 -
 
 
 
 
 П_р_и_м_е_ч_а_н_и_е. Однако, вызов функции strcpy(str,"Hi, the-
 re!") допустим, т.к. в данном случае осуществляется  посимволь-
 ное копирование строки "Hi, there!" в  ячейки  памяти,  опреде-
 ляемые str.
 
 
      1.9.5. Модификатор volatile
 
 
      Модификатор  volatile  -  почти  полная  противоположность
 const. Он указывает, что объект может быть изменен; но не толь-
 ко непосредственно вашей программой, но и  также  внешним  воз-
 действием,    таким   как   программа   прерываний   или   порт
 ввода/вывода. Объявление  объекта  как  volatile  предупреждает
 компилятор, что не нужно делать предположений относительно зна-
 чения объекта, в то время как оцениваются выражения, его содер-
 жащие, т.к. значение может (теоретически)  измениться  в  любой
 момент. Кроме того, использование данного модификатора не  поз-
 воляет компилятору использовать вместо  переменных  регистровые
 переменные.
 
      Примеры:
 
         volatile int ticks;
         interrupt timer();
         {
                 ticks++;
         }
 
         wait (int interval)
         {
                 ticks=0;
                 while(ticks, <=, >=) работают пра-
        вильно с указателями типа huge; но не с указателями типа
        far.
 
      - Все арифметические операции  над  указателем  huge  воз-
        действуют как на адрес сегмента, так и на смещение  (из-
        за нормализации); при  использовании  far  указателей  -
        воздействие только на смещение.
 
      - Заданный указатель типа huge может быть увеличен в  пре-
        делах 1Мб адресного пространства; указатели типа far бу-
        дут при определенных обстоятельствах циклически  перехо-
        дить на начало 64К сегмента.
 
      - При использовании указателей типа huge требуется  допол-
        нительное  время,  т.к.  программы  нормализации  должны
        вызываться после выполнения любой арифметической  опера-
        ции над указателями.
 
 
      1.10. Структуры и объединения (K&R 8.5)
 
 
      Turbo-C обеспечивает следующие дополнительные возможности.
 
 
 
 
 
 
                             - 16 -
 
 
 
 
      1.10.1. Выравнивание слов
 
 
      Если при компиляции используется опция -a,  Turbo-C  будет
 заполнять байтами структуру (или  объединение)  таким  образом,
 как требуется для выравнивания слов. Обеспечивается следующее:
 
      - Структура  будет  начинаться  с  границы  слова  (четный
        адрес).
 
      - Любой член, имеющий не-char тип, будет иметь четное сме-
        щение от начала структуры.
 
      - В конец будет добавлен байт (если необходимо),  для  га-
        рантии того, что структура содержит четное число байт.
 
 
      1.10.2. Битовые поля
 
 
      Битовое поле может иметь тип либо  signed,  либо  unsigned
 int и может занимать от 1 до 16 битов. Битовые поля размещаются
 в направлении от младших к старшим  битам  в  слове.  Например,
 структура
 
         struct mystruct {
                 int             i : 2;
                 unsigned        j : 5;
                 int               : 4;
                 int             k : 1;
                 unsigned        n : 4;
         } a, b, c;
 
 обеспечивает следующее размещение:
 
  __________________________________________________
  |15|14|13|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| x|
  |-----------|---|-----------|--------------|-----|
  |<--------->|<->|<- - - - ->|<------------>|<--->|
  |-----------|---|-----------|--------------|-----|
  |     m     | k |не использ.|       j      |  i  |
  |___________|___|___________|______________|_____|
 
      Поля целого типа хранятся в одной из  двух  форм;  крайний
 левый бит - знаковый бит. Например, битовое  поле  типа  signed
 int шириной 1 бит может только хранить значение -1  и  0,  т.к.
 любое ненулевое значение будет интерпретироваться как -1.
 
 
 
 
 
 
                             - 17 -
 
 
 
 
      1.11. Операторы (K&R 9)
 
 
      Turbo-C выполняет все без исключения операторы,  описанные
 в K&R.
 
 
      1.12. Определение внешних функций (K&R 10.1)
 
 
      Описание extern, заданное внутри функции, имеет действие в
 пределах данного блока. Описание не  будет  распознаваться  вне
 блока,   в  котором  оно  определено.  Однако,  Turbo-C   будет
 "запоминать" описания, для того чтобы сравнивать их с последую-
 щими описаниями тех же самых объектов.
 
      Turbo-C поддерживает дополнительные модификаторы  функций,
 такие как прототипы функций  (ANSI-стандарт).  Существует  нес-
 колько собственных расширений Turbo-C,  например  функции  типа
 interrupt.
 
 
      1.12.1. Модификаторы типа функции (K&R 10.1.1)
 
 
      В дополнение к external и static, Turbo-C поддерживает ряд
 модификаторов типа для описания функций: pascal, cdecl,  inter-
 rupt, near, far и huge.
 
 
      1.12.1.1. Модификатор функции pascal
 
 
      Данный модификатор используется для функций (или  указате-
 лей на функции), которые используют Паскалевскую последователь-
 ность передачи параметров. Это  позволяет  писать  на  языке  C
 функции, которые могут быть вызваны из программ, написанных  на
 другом языке; аналогично, наличие модификатора будет  допускать
 обращение из C-программ, к внешним подпрограммам, написанным на
 других языках. Имя функции преобразуется к  верхнему  регистру,
 что необходимо для работы редактора связей.
 
 П_р_и_м_е_ч_а_н_и_е. Использование опции -p будет  приводить  к
 тому, что все функции (и указатели на эти функции) будут  расс-
 матриваться как если бы они имели тип pascal. Например, если вы
 объявили и откомпилировали следующую функцию:
 
         pascal putnums(unt i, int j, int k)
         {
            printf("And the answers are: %d, %d и %d\n",i,j,k);
         }
 
 другая C-программа может затем подключить  данную  функцию  при
 работе редактора связей и обращаться к ней, используя описание:
 
                             - 18 -
 
 
 
 
 
         pascal putnums(int i, int j, int k);
         main()
         {
                 putnum(1,4,9);
         }
 
      Функции типа pascal не могут иметь различное  число  аргу-
 ментов, как, например, функция printf. По этой  причине  вы  не
 можете использовать эллипсис  (...)  (пропуск  подразумеваемого
 аргумента) в определении функции типа pascal.
 
 
      1.12.1.2. Модификатор функции cdecl
 
 
      Данный модификатор аналогичен модификатору pascal; исполь-
 зуется с функциями или указателями на функции, для  того  чтобы
 отменить директиву компилятора -p и объявить функцию как  обыч-
 ную C-функцию. Например, если вы при компиляции программы уста-
 новили опцию -p, но хотите использовать printf, вы должны  пос-
 тупить следующим образом:
 
         extern cdecl printf();
         putnums(int i, int j, int k);
 
         cdecl main()
         {
                 putnums(1,4,9);
         }
 
         putnums(int i, int j, int k)
         {
            printf("And the answers are: %d, %d и %d\n",i,j,k);
         }
 
      Если программа компилируется с опцией -p, все  функции  из
 системной библиотеки необходимо объявить  как  cdecl.  Если  вы
 посмотрите системные  include-файлы,  то  увидете,  что  каждая
 функция явно описана как cdecl.
 
 П_р_и_м_е_ч_а_н_и_е. Гланая программа (main) должна быть  также
 объявлена cdecl.
 
 
      1.12.1.3. Модификатор функции interrupt
 
 
      Модификатор interrupt  предназначен  для  использования  с
 векторами прерываний процессора 8086/8088. Turbo-C будет компи-
 лировать функцию типа interrupt с дополнительным входом и кодом
 завершения, так что регистры AX, BX, CX, DX, SI, DI,  ES  и  DS
 сохраняются. Другие регистры: BP, SP, SS, CS и  IP  сохраняются
 как часть последовательности C-вызова или часть самой обработки
 
                             - 19 -
 
 
 
 
 прерывания. Рассмотрим пример стандартного определения  функции
 типа interrupt.
 
         void interrupt myhandler()
         {
                 . . .
         }
 
      Желательно объявлять функции прерываний как  функции  типа
 void.   Функции  прерываний  поддерживаются  для  всех  моделей
 памяти. Для всех моделей, исключая huge, в регистр DS заносится
 сегмент данных программы. Для модели huge в  DS  заносится  мо-
 дульный сегмент данных.
 
 
      1.12.1.4. Прототипы функций (K&R 10.1.2)
 
 
      В K&R допускается только объявление функции, состоящее  из
 имени, типа и пустых скобок. Параметры (если они  есть)  объяв-
 ляются только в определении непосредственно самой функции.
 
      ANSI стандарт и Turbo-C допускают использование прототипов
 функций, для того чтобы объявить функцию. Существуют специальн-
 ые описания, которые включают информацию о параметрах  функции.
 Компилятор использует данную информацию  для  проверки  вызовов
 функций, а также для преобразования аргументов  к  требующемуся
 типу. Рассмотрим следующий фрагмент программы:
 
         long lmax(long v1, long v2);
 
         main()
         {
                 int limit=32;
                 char ch='A';
                 long mval;
 
                 mval=lmax(limit,ch);
         }
 
      Задан прототип  функции  для  lmax;  эта  программа  будет
 преобразовывать параметры limit и ch  к  типу  long,  используя
 стандартные правила преобразования, прежде чем они будут  поме-
 щены в стек для обращения  к  lmax.  При  отсутствии  прототипа
 функции параметры limit и ch были бы помещены в стек соответст-
 венно как целое значение и символ; в этом случае в lmax переда-
 вались бы параметры, не совпадающие по размеру и  содержанию  с
 ожидаемыми. Использование прототипов функций позволяет избежать
 ошибок.
 
      Описание функции
 
         f(void)
 
 
                             - 20 -
 
 
 
 
 
 означает, что функция не имеет аргументов.
 
      В противном случае, в скобках указывается список  парамет-
 ров, разделенных запятыми. Объявление может быть сделано в фор-
 ме
 
 
        func(int *, long);
 
 
        или в него могут быть включены идентификаторы
 
 
        func(int * count, long total);
 
      В обоих случаях, указанных выше,  функция  func  принимает
 два параметра: указатель на тип int, названный count,  и  целую
 переменную total типа long. Идентификатор, указанный в объявле-
 нии, используется только в диагностическом сообщении, в  случае
 возникновения несоответствия типа параметров.
 
      Прототип функции обычно определяет  функцию  как  функцию,
 принимающую фиксированное число параметров. Для C-функций,  ко-
 торые принимают различное число параметров (например,  printf),
 пропотип функции может заканчиваться многоточием (...),  напри-
 мер
 
 
        f(int *count, long total, ...)
 
      При такой форме прототипа фиксированные  параметры  прове-
 ряются во время компиляции, а переменные параметры  передаются,
 как при отсутствии прототипа.
 
      Рассмотрим несколько примеров.
 
         int f();        /*  Функция возвращает величину
                             типа int. Это классический
                             стиль K&R */
 
         int f(void);   /* Функция возвращает значение
                         типа int. Явно указано, что параметры
                         не передаются */
 
         int p(int,long);  /* Функция получает два параметра;
                         первый имеет тип int, второй - long */
 
         int pascal q(void); /* Функция Паскалевского типа
                                 без параметров; возвращает
                         значение типа int */
 
         char far * s(char *source, int kind);   /* Функция
                         возвращает указатель типа far на
 
                             - 21 -
 
 
 
 
                         строку; получает два параметра */
 
         int printf(char *format,...);  /* Функция возвращает
                         значение типа int, получая указатель
                         на фиксированный параметр типа char
                         и любое число дополнительных
                         параметров неизвестного типа */
 
         int (*fp)(int);  /* Указатель на функцию, возвращающую
                         значение типа int и получающую
                         единственный int параметр */
 
      Общие правила работы с модификаторами языка и  формальными
 параметрами в вызовах функций, как использующих протопиты,  так
 и их не использующих:
 
 1)     Модификаторы языка для описания функций должны совпадать
        с модификаторами, используемыми  в  объявлении  функции,
        для всех обращений к функции.
 
 2)     Функция может изменять значения  формальных  параметров,
        но это не оказывает какого-либо воздействия на  значения
        действительных аргументов  в  вызывающей  программе,  за
        исключением функций прерывания.
 
      Если прототип функции не объявлен предварительно,  Turbo-C
 преобразует   аргументы  при  обращении  к   функции   согласно
 правилам, описанным в разделе "Арифметические  преобразования".
 Если объявлен прототип, Turbo-C преобразует  аргуметы  к  типу,
 объявленному для параметров.
 
      Если прототип функции включает многоточие  (...),  Turbo-C
 преобразует все заданные аргументы функции к аргументам,  зада-
 ваемым прототипом (до многоточия).  Компилтор  будет  расширять
 любые аргументы, заданные после  фиксированных  параметров,  по
 нормальным правилам для аргументов функций без прототипов.
 
      Если есть прототип, число  аргументов  должно  быть  соот-
 ветственным (за исключением случая, когда  в  прототипе  опущен
 какой-либо аргумент). Типы должны  быть  совместимы  только  по
 размеру, для того чтобы корректно производились  преобразования
 типов. Вы всегда должны использовать явные преобразования аргу-
 ментов к типу, допустимому для прототипа функции.
 
      ПРИМЕР:
 
 int strcmp(char *s1, char *s2);   /* Полный прототип */
 int *strcpy();                    /* Нет прототипа */
 int samp1(foat, int, ...);        /* Полный прототип */
 
 samp2()
 {
         char *sx, *cp;
         double z;
 
                             - 22 -
 
 
 
 
         long a;
         float q;
 
         if(strcmp(sx, cp))    /* 1. Верно */
           strcpy(sx, cp, 44); /* 2. Идет только для Turbo-C */
         samp1(3, a, q);       /* 3. Верно */
         strcpy(cp);           /* 4. Ошибка при выполнении */
         samp1(2);             /* 5. Ошибка при компиляции */
 }
 
      В 1 вызове (см. нумерацию  в  комментариях)  использование
 функции strcmp явно соответствует  прототипу  и  корректно  для
 всех случаев.
 
      Во 2 вызове (strcpy) имеется лишний аргумент (strcpy опре-
 делена для двух аргументов, а не для 3-ех). В этом случае  Tur-
 bo-C теряет небольшое количество времени и генерит код для  по-
 мещения лишнего аргумента в стек. Это, однако, не является син-
 таксической ошибкой, т.к. компилятор не знает о числе  аргумен-
 тов strcpy. Такой вызов не допустим для других компилиторов.
 
      В 3-ем примере прототип  требует,  чтобы  1  аргумент  для
 samp1 был преобразован к float, а  2-ой  -  к  int.  Компилятор
 выдаст предупреждение о возможной потере значимых цифр вследст-
 вие того, что при преобразовании типа long к типу int  отбрасы-
 ваются верхние биты. Вы можете избавиться от выдачи такого пре-
 дупреждения, если зададите явное преобразование к целому.  Тре-
 тий   аргумент,  q,  соответствует   опущенному   аргументу   в
 прототипе. Он преобразуется к  типу  double  согласно  обычному
 арифметическому преобразованию. Весь вызов корректен.
 
      В 4 вызове снова встречается обращение к strcpy, но  число
 аргументов слишком мало.  Это  вызовет  ошибку  при  выполнении
 программы. Компилятор же ничего не сообщит (если даже число па-
 раметров отличается от числа параметров в предыдущем вызове той
 же функции), т.к. для strcpy нет прототипа функции.
 
      В 5 вызове для функции samp1 задано слишком мало  аргумен-
 тов. Т.к. samp1 требует минимум 2 аргумента, этот оператор  яв-
 ляется ошибочным. Компилятор выдаст  сообщение  о  том,  что  в
 вызове не хватает аргументов.
 
 П_р_и_м_е_ч_а_н_и_е. Если ваш прототип функции не соответствует
 действительному определению функции, Turbo-C  обнаружит  это  в
 том и только в том случае, если это определение находится в том
 же файле, что и прототип. Если вы создаете библиотеку  программ
 с соответствующим  сборником  прототипов  (include-файлом),  вы
 должны учитывать включение файла с прототипами во время  компи-
 ляции библиотеки, для того чтобы  отловить  любое  противоречие
 между прототипами и действительными определениями функций.
 
 
 
 
 
                             - 23 -
 
 
 
 
      1.13. Правила видимости (K&R 11)
 
 
      Правила видимости - это  правила,  определяющие,  в  каких
 частях текста программы может быть  использована  переменная  в
 зависимости от того, где и как она описана.
 
      Turbo-C разрешает более вольное обращение с  неуникальными
 идентификаторами, чем того  требует  K&R.  Различают  4  класса
 идентификаторов:
 
      Имена, описываемые с помощью  слова  typedef,  переменные,
 члены перечисления должны быть уникальными внутри блока, в  ко-
 тором они описаны. Идентификаторы, объявленные внешними, должны
 быть уникальными среди переменных, описанных как внешние.
 
      Структура, объединение, признаки перечисления должны  быть
 уникальными внутри блока, в котором они описаны. Признаки, опи-
 санные вне пределов какой-либо функции, должны  быть  уникальны
 среди всех признаков, описанных как внешние.
 
      Имена структуры и члена объединения должны быть  уникальны
 в структуре или объединении, в которых они описаны. Не  сущест-
 вует никаких ограничений на тип или смещение для членов с  оди-
 наковым именами в различных структурах.
 
      Операторы GOTO на метку должны использоваться лишь  в  той
 функции, где объявлена данная метка.  Метка,  в  свою  очередь,
 должна быть уникальна для функции, в которой она объявлена.
 
 
      1.14. Команды управления трансляцией (R&K 12)
 
 
      Turbo-C поддерживает все управляющие команды, описанные  в
 K&R. Этими командами являются директивы препроцессора -  строки
 исходной программы, начинающиеся со знака #.
 
 
      1.14.1. Замена лексем (K&R 12.1)
 
 
      Turbo-C выполняет все определения #define и  #undef,  опи-
 санные в R&K, со следующими дополнениями:
 
      1. Следующие идентификаторы не обязательно  должны  встре-
 чаться в директивах #define и #undef:
 
      _STDC_
 
      _FILE_
 
      _LINE_
 
 
                             - 24 -
 
 
 
 
 
      _DATE_
 
      _TIME_
 
      2. В макроопределение могут  быть  вставлены  две  лексемы
 вместе, разделенные знаками ##, например:
 
      #define VAR(i,j) (i ## j)
 
      При этом VAR(x,6) вызовет  подстановку  x6.  Это  заменяет
 иногда употребляемый, но  не  переносимый  метод  использования
 (i/**/j).
 
      3. Вложенные макросы в строке макро-определения  сработают
 лишь тогда, когда сработает сам макрос, а не при его  описании.
 Это больше касается вложенных макросов #undef.
 
      4. Символ #, помещаемый перед макроаргументом, указывает о
 преобразовании его в строку. При макроподстановке  производится
 замена #<формальный аргумент> на  "<действительный  аргумент>".
 Так, при задании макроопределения
 
      #define TRACE(flag) printf(#flag "= %d\n", flag)
 
      следующий фрагмент текста программы
 
      highval = 1024;
 
      TRACE(highval);
 
      преобразуется:
 
      highval = 1024;
 
      printf("highval" "= %d\n", highval);
 
      5. В отличие от других реализаций, Turbo-C не осуществляет
 подстановок макроаргументов внутри строк и символьных констант.
 
 
      1.14.2. Включение файла (K&R 12.2)
 
 
      Turbo-C использует директиву так же, как описано в K&R, но
 существуют некоторые дополнительные особенности:  Если  препро-
 цессор не нашел include-файл в каталоге, установленном по умол-
 чанию (преполагается, что вы используете форму
 
      include "filename"), тогда он ищет каталоги, заданные  оп-
 цией   компилятора  -I.  Если  вы  используете  форму  #include
 , тогда ищутся только каталоги, заданные  опцией  -I.
 (Каталоги, перечисляемые в меню по опции O/Environment/Include,
 эквивалентны каталогам, заданным с помощью опции -I pathname  в
 
                             - 25 -
 
 
 
 
 командной строке.
 
      Вы можете задать имя пути #include,  включающее  граничные
 разделители, используя макрорасширение. Если  следующая  строка
 после ключевого слова начинается с идентификатора, препроцессор
 просматривает текст для макроса. Однако, если строка  заключена
 в кавычки или в угольные скобки, Turbo-C не будет проверять  ее
 для запоминания макроса. Например,
 
      #define myinclude "c:\tc\include\mystuff.h"
 
      #include myinclude
 
      #include "myinclude"
 
      1-ый #include-оператор заставит препроцессор просматривать
 C:\TC\INCLUDE\MYSTUFF.H, тогда как 2-ой вызовет просмотр MYINC-
 LUDE.H в каталоге по умолчанию.
 
      Вы можете не использовать  объединение  литерных  строк  и
 вставку лексем в  макросе,  который  используется  в  операторе
 include. Макрорасширение должно генерить текст, который читает-
 ся как нормальная #include-директива.
 
 
      1.14.3. Условная компиляция (K&R 12.3)
 
 
      Turbo-C поддерживает определение условной компиляции K&R с
 помощью замены соответствующих строк на пустые. Строки, игнори-
 руемые т.о., начинаются с директив #if, #ifdef, #ifndef, #else,
 #elif,
 
      endif, также как и все некомпилируемые строки,  являющиеся
 результатом этих директив. Все  директивы  условной  компиляции
 должны заканчиваться в исходной программе или include-файле,  в
 которых они начались.
 
        Turbo-C  поддерживает  также   оператор   ANSI-стандарта
 defined(symbol). Присваивается значение 1 (true),  если  символ
 был предварительно определен (с использованием #define) и затем
 не был отменен (с использованием
 
      undef); иначе присваивается 0 (false). Так, директива
 
      #if defined(mysym)
 
      адекватна директиве
 
      #ifdef mysym
 
      Преимуществом этого является  возможность  повторного  ис-
 пользования defined в сложном выражении, стоящем  после  дирек-
 тивы #if:
 
                             - 26 -
 
 
 
 
 
      #if defined(mysym) || defined(yoursym)
 
      Turbo-C (в отличие от  ANSI)  позволяет  вам  использовать
 оператор sizeof в выражении для препроцессора:
 
      #if (sizeof(void *) ==2)
      #define SDATA
      #else
      #define LDATA
      #endif
 
 
      1.14.4. Управление строками (K&R 12.4)
 
 
      Turbo-C поддерживает определение #line, данное в K&R.
 
 
      1.14.5. Директива обработки ошибок (ANSI C 3.8.5)
 
 
      Turbo-C поддерживает директиву #error, которая упоминается
 (но не определяется) в ANSI-стандарте. Ее формат:
 
      #error errmsg
 
      Если вы включите эту директиву условной компиляции в  файл
 с вашей исходной программой и условные тестовые файлы,  препро-
 цессор будет считывать директиву #error и немедленно прерывать-
 ся, выдавая при этом следующее сообщение:
 
      Fatal: filename line# Error directive: errmsg
 
      Препроцессор просматривает текст для того,  чтобы  уничто-
 жить комментарии, но на  экран  выводит  оставшийся  текст  без
 просмотра для выявления макросов.
 
 
      1.14.6. Директива PRAGMA (ANSI C 3.8.6)
 
 
      Turbo-C поддерживает директиву #pragma, которая (как и
 
      error), неясно определяется в ANSI-стандарте. Ее целью яв-
 ляется разрешить специализированные директивы:
 
      #pragma 
 
        С  помощью  #pragma  Turbo-C  может   определить   любые
 директивы, которые ему требуются, без вмешательства других ком-
 пиляторов, которые поддерживают #pragma.  По-определению,  если
 компилятор не опознал имя директивы,  он  игнорирует  директиву
 pragma.
 
                             - 27 -
 
 
 
 
      1.14.6.1. #pragma inline
 
 
      Turbo-C распознает две директивы #pragma. Первая:
 
      #pragma inline
 
      Эта директива эквивалентна опции компилятора -B. Она сооб-
 щает компилятору о том, что в вашей программе присутствуют  ас-
 семблеровские машинные команды. Наилучшее ее положение - в  на-
 чале файла, т.к. компилятор  самоперезапускается  с  опцией  -B
 сразу, как только встретится #pragma inline. На самом деле,  вы
 можете опустить и опцию -B, и директиву  #pragma  inline,  т.к.
 компилятор все равно сомоперезапускается, как  только  встретит
 asm-операторы; целью этой опции и директивы  является  экономия
 времени компиляции.
 
 
      1.14.6.2. #pragma warn
 
 
      Другая #pragma-директива - это
 
      pragma warn
 
      Данная директива позволяет вам не  принимать  во  внимание
 специальную опцию командной строки -wxxx (опция включения  спе-
 циальных предупредительных сообщений).
 
      Например, если ваша исходная программа содержит директивы:
 
      #pragma warn +xxx
      #pragma warn -yyy
      #pragma warn .zzz
 
      то xxx включит выдачу  предупредительных  сообщений  (если
 даже в подменю O/C/Errors/ она была  выключена);  yyy  выключит
 выдачу сообщений; а zzz  восстановит  первоначальное  значение,
 которое было в начале компиляции файла.
 
      Окончательный список 3-буквенных аббревиатур и  сообщений,
 которые они включают  и  выключают,  приведен  в  Приложении  3
 Ссылочного Руководства по Turbo-C.
 
 
      1.14.7. Нулевая директива (ANSI C 3.7)
 
 
      Ради завершенности, ANSI-стандарт и Turbo-C опознают  пус-
 тую директиву, состоящую из строки, содержащей просто  знак  #.
 Эта директива всегда игнорируется.
 
 
 
 
                             - 28 -
 
 
 
 
      1.14.8. Встроенные макро-имена
 
 
      ANSI-стандарт требует 5 встроенных макросов. Turbo-C  при-
 меняет все 5. Отметим, что каждый из них начинается  и  оканчи-
 вается символом подчеркивания (__).
 
 _LINE_
        Номер обрабатываемой строки исходной программы  -  деся-
        тичная константа. Первая строка исходного файла  опреде-
        лена как 1.
 
 _FILE_
        Имя обрабатываемого исходного файла - литерная строка.
 
        Данное макроопределение изменяется всякий раз, как  ком-
        пилятор обрабатывает директиву  #include  или  директиву
        line, или когда закончился #include-файл.
 
 _DATE_
        Дата начала обработки текущего исходного файла -  литер-
        ная строка.
 
        Каждое вхождение _DATE_ в заданный файл гарантирует одно
        значение, независимо от того, как долго уже продолжается
        обработка. Дата имеет формат mmmddyyyy, где mmm -  месяц
        (Jan, Feb и т.д.), dd - число текущего месяца (1...31; в
        1-ой из двух позиций  dd  ставится  пробел,  если  число
        меньше 10), yyyy - год (1987, 1988 и т.д.).
 
 _TIME_
        Время начала обработки текущего исходного файла - литер-
        ная строка.
 
        Каждое вхождение _TIME_ в заданный файл гарантирует одно
        значение, независимо от того, как долго уже продолжается
        обработка. Время имеет формат hh:mm:ss,  где  hh  -  час
        (00...23),   mm  -  минуты  (00...59),  ss   -   секунды
        (00...59).
 
 _STDC_
        Константа, равная 1, если вы компилируете с  флагом  -a,
        который устанавливает  совместимость  с  ANSI-стандартом
        (ANSI keywords only ... ON); иначе  макроопределение  не
        определено.
 
 
      1.14.9. Встроенные макросы Turbo-C
 
 
      Препроцессор Turbo-C определяет  различные  дополнительные
 макросы. Также, как для макросов, предписанных ANSI-стандартом,
 каждый из них начинается и оканчивается символом  подчеркивания
 (__).
 
                             - 29 -
 
 
 
 
 
 _TURBOC_
        Выдача номера текущей версии Turbo-C -  шеснадцатеричная
        константа. Версия 1.0 представляется как 0x0100;  версия
        1.2 - как 0x0102 и т.д.
 
 _PASCAL_
        Определяет значение флага -p;  устанавливается  в  целую
        константу, равную 1, если используется флаг -p; иначе не
        определено.
 
 _MSDOS_
        Целая константа, равная 1.
 
 _CDECL_
        Определяет значение флага -p;  устанавливается  в  целую
        константу, равную 1, если флаг -p не используется; иначе
        не определено.
 
      Следующие 6 макросов зависят от выбранной  для  компиляции
 модели памяти. Для любой компиляции определен может быть только
 один   из  них;  остальные  (по-определению)   не   определены.
 Например, если вы компилируете с маленькой моделью,  определено
 _SMALL_,   а   остальные   -   нет;   поэтому   директива   #if
 defined(_SMALL_) будет иметь значение true(верно), в  то  время
 как #if defined(_HUGE_) (или любая другая) будет иметь значение
 fulse(ложно). Действительное значение для любого  определенного
 макроопределения равно 1.
 
 _TINY_
        Опции выбора крошечной модели памяти.
 
 _SMALL_
        Опции выбора маленькой модели памяти.
 
 _MEDIUM_
        Опции выбора средней модели памяти.
 
 _COMPACT_
        Опции выбора компактной модели памяти.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                             - 30 -
 
 
 
 
                    2. Модели памяти Turbo-C
 
 
 
 
 
      Turbo-C поддерживает шесть различных моделей памяти: tiny,
 small, medium, compact, large и huge.
 
 tiny
        Это самая малая модель памяти. Все четыре регистра ( CS,
        DS, SS, ES) содержат один и тот же  адрес,  поэтому  64К
        выделяются для хранения кода, данных и массивов.  Всегда
        используются указатели типа near. Программы,  использую-
        щие модель памяти tiny, могут быть преобразованы к  фор-
        мату .COM.
 
      На приведенном ниже рисунке показано распределение памяти.
 
 Сегментные                                  Размер
 регистры                                    сегмента
                   +------------------------+
 CS, DS, ES, SS ---|         DGROUP         | до 64К байт
                   +------------------------+
                   |  _TEXT класс 'DATA'    |
                   |        код             |
                   +------------------------+
                   |  _DATA класс 'DATA'    |
                   |  инициализированные    |
                   |         данные         |
                   +------------------------+
                   |  _BSS класс 'BSS'      |
                   |  инициализированные    |
                   |         данные         |
                   +------------------------+
                   |          Куча          |
             SP ---+------------------------+
                   |          Стек          |
                   +------------------------+
 
                 Сегментация памяти модели tiny
 
 П_р_и_м_е_ч_а_н_и_е. Описание остальных моделей памяти приведе-
 но в Справочном руководстве по компилятору MSC.
 
 
      2.1.   Использование    смешанных    моделей    памяти:
           модификаторы адресации
 
 
      Turbo-C поддерживает семь новых ключевых  слов,  неопреде-
 ленных в K&R и стандарте ANSI: near, far, huge, _cs, _ds,  _es,
 _ss. Они могут быть использованы с определенными  ограничениями
 как модификаторы для указателей  (и  в  некоторых  случаях  для
 
                             - 31 -
 
 
 
 
 функций).
 
      В Turbo-C можно изменять функции и указатели  с  ключевыми
 словами near, far или huge. К функциям типа near (far,huge) об-
 ращаются с помощью near (far, huge) вызовов  и  они  возвращают
 тип near (far, huge).
 
 П_р_и_м_е_ч_а_н_и_е. Функции типа huge могут установить регист-
 ре DS в новое значение, в отличие от функций остальных типов.
 
      Для данных,  имеющих  тип  near,  существуют  четыре  спе-
 циальных указателя: _cs, _ds, _ss и _es. Это 16-битовые  указа-
 тели, которые особым образом связаны  с  соответствующими  сег-
 ментными регистрами. Например, если объявить
 
      char _ss *p;
 
 то p содержит 16-битовое смещение в стековом сегменте.
 
      Функции и указатели в программе будут по  умолчанию  иметь
 тип near или  far,  в  зависимости  от  выбранной  вами  модели
 памяти. Если функция или указатель имеет тип near, то они авто-
 матически связываются с регистром CS или DS.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                             - 32 -
 
 
 
 
       3. Использование различных языков программирования
 
 
 
 
 
 
      3.1. Смешение языков программирования: интерфейс
 
 
        Turbo-C  позволяет  из  программ  на  C   обращаться   к
 программам, написанным на других языках, и наоборот.  В  данном
 подразделе рассмотрен интерфейс Turbo-C с другими языками.
 
 
      3.1.1.  Последовательности  передачи  параметров:  C  и
             Паскаль
 
 
      Turbo-C поддерживает  два  метода  передачи  параметров  в
 функцию: стандартный C-метод и паскалевский метод.
 
 
      3.1.1.1.   C-последовательность   передачи   параметров
               (соглашение вызова)
 
 
      Предположим вы объявили следующий прототип функции:
 
      void funca(int p1, int p2, int p3);
 
      По умолчанию, Turbo-C использует C-последовательность  пе-
 редачи параметров. При обращении к данной функции (funca) пара-
 метры помещаются в стек в порядке справа-налево (p3,  p2,  p1),
 следом за параметрами в стек помещается адрес  возврата.  Расс-
 мотрим фрагмент программы:
 
         main()
         {
                 int i, j;
                 long k;
                 . . .
                 i=5; j=7; k=0x1407AA;
                 funca(i,j,k)
                 . . .
         }
 
      Стек будет выглядеть следующим образом:
 
         SP + 06:        0014
         SP + 04:        07AA   k=p3
         SP + 02         0007   j=p2
         SP              0005   i=p1
 
 
                             - 33 -
 
 
 
 
 П_р_и_м_е_ч_а_н_и_е. Стек растет сверху вниз, поэтому i - теку-
 щий "верх" стека.
 
      Вызывающая программа не выбирает параметры из  стека,  это
 будет делать вызываемая программа.
 
      Рассмотрим фрагмент программы на языке ассемблера, который
 получен при компиляции исходной программы на языке C, приведен-
 ной выше.
 
         mov     word prt [bp-8],5     ; Установка i=5
         mov     word prt [bp-6],7     ; j=7
         mov     word prt [bp-4],0014h ; k=0x1407AA
         mov     word prt [bp-2],07AAh
         push    word prt [bp-2]       ; Помещаем указатель
                                 ; стека на старшее слово k
         push    word prt [bp-4]       ; Помещаем указатель
                                 ; стека на младшее слово k
         push    word prt [bp-6]  ; Указатель стека - на j
         push    word prt [bp-8]  ; Указатель стека - на i
         call    near prt funca   ; Вызов функции funca
         add     sp,8             ; Установка стека
 
 
      Последняя команда add sp,8. В данной точке компилятор  уз-
 нает точно сколько параметров было помещено в стек; узнает  ад-
 рес возврата, который был помещен в стек посредством  обращения
 к funca.
 
 
      3.1.1.2.   Паскалевская   последовательность   передачи
               параметров (соглашение вызова)
 
 
      Данный метод не означает, что вы можете  вызывать  функции
 Turbo-Паскаля из Turbo-C.
 
      Если функция объявлена как
 
         void pascal funca(int p1, int p2, int p3);
 
 при обращении к функции последовательность помещает параметры в
 стек слева-направо, т.е. в порядке (p1, p2, p3). Затем  в  стек
 помещается адрес возврата.
 
      Рассмотрим фрагмент программы:
 
         main()
         {
                 int i, j;
                 long k;
                 . . .
                 i=5; j=7; k=0x1407AA;
                 funca(i,j,k)
 
                             - 34 -
 
 
 
 
                 . . .
         }
 
      Стек будет выглядеть следующим образом:
 
         SP + 06:        0005   i=p1
         SP + 04:        0007   j=p2
         SP + 02         0014
         SP              07AA   k=p3
 
 
      Паскалевская последовательность передачи параметров  пред-
 полагает, что вызванной программе (funca) известно сколько  па-
 раметров передается, и в соответствии с этим заполняется  стек.
 Другими словами, на языке ассемблера обращение к функции  funca
 будет выглядеть следующим образом:
 
         push    word prt [bp-8]    ; Помещаем i
         push    word prt [bp-6]    ; Помещаем j
         push    word prt [bp-4]    ; Помещаем старшее
                                 ; слово k
         push    word prt [bp-2]       ; Помещаем
                                 ; младшее слово k
         call    near prt funca   ; Вызов функции funca
                                 (помещаем адрес возврата)
 
      Заметим, что в данном случае отсутствует команда add  sp,8
 после вызова. Вместо этого funca использует команду ret 8,  для
 того чтобы очистить стек перед возвратом в main.
 
      По умолчанию все функции Turbo-C используют C-метод  пере-
 дачи параметров. Если вы используете флаг -p при компиляции,  в
 этом случае все  функции  используют  паскалевский  метод.  Для
 того, чтобы задать использование C-метода для какой-дибо  функ-
 ции, используйте модификатор cdecl.
 
      Например,
 
         void cdecl funca(int p1, int p2, int p3);
 
      Паскалевский метод используется в следующих случаях:
 
 1)     При использовании вызовов существующих программ  на  ас-
        семблере, использующих данное соглашение вызова
 
 2)     При использовании программ, написанных на других  языках
        программирования.
 
 3)     the calling code produced is slightly smaller, since  it
        doesn't have to clean up the stack afterwards.
 
 
 
 
 
                             - 35 -
 
 
 
 
      3.1.2. Интерфейс с ассемблером
 
 
 
      3.1.2.1. Обращения к файлам .ASM из Turbo-C
 
 
      Вы можете писать ассемблеровские программы  как  отдельные
 модули, для того чтобы в последствии их связывать с  C-програм-
 мами. Однако, существуют определенные  соглашения,  которым  вы
 должны следовать, для того чтобы:
 
 1)     быть уверенным, что редактор связей получит всю  необхо-
        димую информацию;
 
 2)     быть уверенным, что формат файла находится в  соответст-
        вии с моделью памяти, используемой вашей C-программой.
 
 
                                                       Таблица 5
 
                    Общая структура программы
 
 -------------------------------------------------------
 Идентификатор   Имя             Имя файла
 -------------------------------------------------------
           SEGMENT         BYTE PUBLIC 'CODE'
                 ASSUME          CS: , DS: 
                 <...........сегмент кода..............>
           ENDS
 
           GROUP           _DATA, _BSS
           SEGMENT         WORD PUBLIC 'DATA'
                 <..сегмент инициализированных данных..>
           ENDS
 
 _BSS            SEGMENT         WORD PUBLIC 'BSS'
                 <.сегмент неинициализированных данных.>
 _BSS            ENDS
 
 _BSS            END
 
      Идентификаторы , ,  в данной схеме имеют
 особые значения, зависящие от  используемой  модели  памяти.  В
 приведенной ниже таблице указаны соответствующие  значения  для
 каждой модели памяти; filename в данной таблице - это имя моду-
 ля; оно должно использоваться в  директиве  NAME  и  содержимом
 идентификатора.
 
      Заметим, что в модели huge не используется сегмент _BSS, и
 определение GROUP полность пропущено.
 
      Наиболее удобно создать шаблон на ассемблере, откомпилиро-
 вав программу, используя TCC с опцией  -s,  и  посмотреть  файл
 
                             - 36 -
 
 
 
 
 .ASM, в котором хранится сгенеренный ассемблерный код.
 
 
                                                       Таблица 6
 
           Содержимое идентификаторов и модели памяти
 
 ---------------------------------------------------------
 Модель          Содержимое              Код и указатели
                 индентификатора
 ---------------------------------------------------------
 tiny, small     =_TEXT          Code: DW _TEXT:xxx
                 =_DATA          Data: DW DGROUP:xxx
                 =DGOUP
 
 compact         =_TEXT          Code: DW _TEXT:xxx
                 =_DATA          Data: DD DGROUP:xxx
                 =DGOUP
 
 medium          =filename_TEXT  Code: DD xxx
                 =_DATA          Data: DW DGROUP:xxx
                 =DGOUP
 
 large           =filename_TEXT  Code: DD xxx
                 =_DATA          Data: DD DGROUP:xxx
                 =DGOUP
 
 huge            =filename_TEXT  Code: DD xxx
                 =filename_DATA  Data: DD xxx
                 =filename_DATA
 
 
      3.1.2.2. Определение констант и переменных
 
 
      Модель памяти влияет также на определение  любых  констант
 данных, таких как указатели на коды, данные.  Приведенная  выше
 таблица показывает как должны выглядеть такие указатели; xxx  -
 адрес, на который ссылается указатель. Заметим,  что  некоторые
 указатели используют DW (Определяют слово), в то время как дру-
 гие используют DD (Определяют двойное слово),  указавая  размер
 результирующего указателя. Цифровые и текстовые константы опре-
 деляются стандартным образом.
 
      Переменные определяются также как и константы. Если вы хо-
 тите завести переменные, которые не имеют начального  значения,
 вы должны объявить их в сегменте _BSS, задав знак (?), когда вы
 желаете ввести значение.
 
 
 
 
 
 
 
                             - 37 -
 
 
 
 
      3.1.2.3.    Определение    глобальных     и     внешних
               идентификаторов.
 
 
      Программа на ассемблере может вызывать функции и ссылаться
 на переменные Turbo-C.  Все  идентификаторы  в  ассемблеровской
 программе, на которые вы хотите ссылаться из Turbo-C программы,
 должны начинаться с символа подчеркивания (_).
 
      Для того чтобы идентификатор, имя подпрограммы  или  пере-
 менная была доступна из-вне вашего ассемблеровского модуля,  вы
 должны объявить их как PUBLIC. Например, если вы  написали  мо-
 дуль, который содержит целые функции min и max  и  целые  пере-
 менные MAXINT, lastmax и lastmin, вы  должны  в  вашем  кодовом
 сегменте задать оператор
 
      PUBLIC _min, _max
 
 и операторы
 
 PUBLIC _MAXINT, _lastmax, _lastmin
 _MAXINT DW 32767
 _lastmin DW 0
 _lastmax DW 0
 
 
      3.1.3. Обращения к Turbo-C из файла .ASM
 
 
 
      3.1.3.1. Ссылка на функции
 
 
      Если вы хотите вызвать С-функцию из программы на ассембле-
 ре, вы должны задать в модуле следующий оператор:
 
      EXTRN  : 
 
 где  - имя функции,  - либо near, либо far, в за-
 висимости от того, имеет ли С-функция тип near  или  far.  Если
  - near, то оператор EXTRN должен появляться внутри  ко-
 дового сегмента вашего модуля; если же far, то  оператор  EXTRN
 должен появляться вне любого сегмента. Например, если вы имеете
 следующий кодовый сегмент:
 
      EXTRN _myfunc1:near, myfunc2:far
 
 это позволит вам вызывать myCfunc1 и myCfunc2 изнутри ваших ас-
 семблеровских программ.
 
 
 
 
 
 
                             - 38 -
 
 
 
 
      3.1.3.2. Ссылка на данные
 
 
      Для того чтобы сослаться на переменные, вы  должны  помес-
 тить операторы EXTRN внутри вашего сегмента  данных,  используя
 следующий формат
 
      EXTRN  : 
 
 где  - имя переменной и  - один из следующих иден-
 тификаторов, указывающий размер переменной:
 
 1)     BYTE (1 байт)
 
 2)     WORD (2 байта)
 
 3)     DWORD (4 байта)
 
 4)     QWORD (8 байт)
 
 5)     TBYTE (10 байт)
 
 
      3.1.4. Встроенный ассемблер
 
 
      Для того чтобы использовать встроенный ассемблер в С-прог-
 рамме, вы можете использовать опцию -B при компиляции. Если  вы
 не используете данную опцию, а компилятор встречает  встроенный
 ассемблер, будет выдаваться предупреждение.
 
      Вы должны иметь MASM версии 3.0 и старше. Компилятор  сна-
 чала создает файл на ассемблере, а затем подключает  MASM,  для
 получения файла .OBJ.
 
      Необходимо использовать ключевое слово  asm  для  введения
 ассемблеровских команд. Формат
 
      asm   <; or newline>
 
 где
 
 
        допустимая команда 8086
 
 
        операдны; можно ссылаться на С константы,  переменные  и
        метки
 
 <; or newline>
        (;) или новая строка - один из признаков конца оператора
        asm.
 
      (;) не может быть использована как начало комментария  как
 
                             - 39 -
 
 
 
 
 в MASM. Используйте С-комментарии. Например
 
         asm mov ax, ds;      /* Допустимый комментарий */
         asm pop ax; asm pop ds; asm iret;
         asm push ds;
 
      Каждый asm-оператор считается как С-оператор. Например,
 
         myfunc()
         {
                 int i;
                 int x;
                 if(i>0)
                         asm mov x,4
                 else
                         i=7;
          }
 
      Заметим, что нет (;) после команды mov x,4. Это допустимый
 if.
 
      Ассемблеровский оператор может быть использован как выпол-
 няемый оператор внутри функции, так и как внешнее описание  вне
 функции. Операторы, помещенные вне функции размещаются  в  сег-
 менте DATA, операторы, помещенные внутри функции, - в  сегменте
 CODE.
 
      Рассмотрим пример встроенной функции min.
 
         int min (int V1, int V2)
         {
                 asm mov ax, V1
                 asm cmp ax, V2
                 asm jle minexit
                 asm mov ax,V2
                 minexit:
                 return(_AX);
         }
 
      Данный пример работает для модулей, использующих  large  и
 small модели памяти, С и Паскалевские соглашения вызова.
 
      Существуют четыре класса  команд  встроенного  ассемблера,
 допустимых Turbo-C:
 
      1) стандартные команды
 
      2) команды работы со строками
 
      3) команды перехода
 
      4) ассемблерные директивы - определения и команды размеще-
 ния данных (db, dd, dw, extrn)
 
 
                             - 40 -
 
 
 
 
      3.1.4.1. Ссылки на  данные  и  функции  из  встроенного
               ассемблера
 
 
      ВСТРОЕННЫЙ АССЕМБЛЕР и РЕГИСТРОВЫЕ ПЕРЕМЕННЫЕ:
 
      Если описания register встречаются в функции, они рассмат-
 риваются как описания регистровых переменных,  во  всех  других
 случаях данные описания рассматриваются как описания  автомати-
 ческих переменных. В недопустимых случаях ключевое слово regis-
 ter игнорируется.
 
      Только short, int (или соответствующие unsigned типы) и 2-
 байтовые указатели могут быть помещены в регистры. Для  регист-
 ровых переменных используются SI и DI регистры.
 
        Если  используется  регистровое  описание   в   функции,
 встроенный ассемблер может использовать или  изменить  значения
 регистровой переменной, используя DI или SI; самое лучшее испо-
 пользовать С символьные имена в случае изменения  значения  ре-
 гистровых переменных.
 
 
      3.1.4.2. Использование структур
 
 
      Во встроенном  ассемблере  можно  использовать  ссылки  на
 структуры. Кроме того, можно непосредственно ссылаться на  член
 структуры. Рассмотрим следующую программу.
 
         struct myStruct {
                 int a_a;
                 int a_b;
                 int a_c;
         } myA;
 
         myfunc()
         {
                 ...
                 asm mov ax, myA.a_b
                 asm mov bx,[di].a_c
                 ...
         }
 
      Первая строка asm засылает в регистр AX значение  myA.a_b.
 Следующая з   засылает   значение,   находящееся   по    адресу
 [DI]+смещение(a_c) (берется адрес, находящийся в регистре DI, и
 добавляется к смещению a_c от начала структуры) в регистр BX.
 
      Эта последовательность операторов порождает следующий код
 
         mov ax, DGROUP:myA+2
         mov bx,[di+4]
 
 
                             - 41 -
 
 
 
 
      3.1.4.3. Использование команд перехода и меток
 
 
      Можно использовать команды условного и безусловного  пере-
 хода, и циклы во встроенном ассемблере.  Они  допустимы  только
 внутри функции. Команды перехода должны использовать метки опе-
 ратора С goto.
 
      Допускается косвенный переход. Вы можете использовать  ре-
 гистровое имя как операнд в команде перехода или заключить опе-
 ранд в скобки [], определяя JUMP-адрес.
 
      Например
 
         int x()
         {
                 int a;
                 . . .
         a:
                 . . .
                 asm jmp a    /* переход на метку "a" */
                 asm jmp [a]  /* переход по адресу,
                                 содержащемуся в "а" */
                 . . .
         }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 



Яндекс цитирования