.pl 54
.со
.ан
# В данном пособии описаны некоторые распространенные
реализации языка Си. Указано отличия реализации от языка, описанного
в [1] (далее в тексте эта книга обозначена как K&R),
вызов компилятора и редактора связей.
.зр Компиляторы языка Си для ОС MS-DOS
.зп 1
Компилятор фирмы BORLAND Turbo-C V1.5
# Turbo-C поддерживает не только определения, данные в K&R, но
и большинство расширений ANSI-стандарта.
В данном разделе приведены дополнения к K&R;
ссылки даны на соответствующие разделы приложения
"Справочное руководство по языку C".
.зп 2
Комментарии
(K&R 2.1)
# Допускаются вложенные комментарии. В этом случае программа должна компилироваться
с флагом -C. Для обеспечения мобильности удобнее отмечать код,
который должен быть закомментирован, директивами #if 0 и #endif.
.зп 2
Идентификаторы
(K&R 2.2)
# В идентификаторах допускается знак $. Однако идентификатор может
начинаться только с буквы или символа (_).
Значащими являются первые 32 символа идентификатора.
Для изменения числа значащих символов можно использовать
при компиляции опцию -i#.
# 32 символа являются значащими  и для глобальных идентификаторов,
берущихся из других модулей.
.зп 2
Ключевые слова
(K&R 2.3)
# Ниже приведены ключевые слова, зарезервированные
Turbo-C (TC) и расширениями ANSI-стандарта (AN).
Данные слова не могут быть использованы в качестве имен идентификаторов.
Ключевые слова entry и fortran, упомянутые в K&R, не используются
в Turbo-C.
.sw
        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
.зп 2
Константы
(K&R 2.4)
# Turbo-C поддерживает все типы констант, определенные в K&R, с
некоторыми расширениями.
.зп 2
Целые константы
(K&R 2.4.1)
# Допускаются десятичные константы в диапазоне 0...4294967295.
(Отрицательные константы рассматриваются как беззнаковые,
к которым применен унарный оператор "минус".
# Суффикс U (или u), означает что константа имеет тип
unsigned. Константа будет иметь тип
unsigned long, если ее значение будет превышать
65535, независимо от используемого основания.
.пр Можно использовать как L, так и U суффиксы
для одной и той же константы.
.тм 3  Целые константы 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                 будет переполнение
.зп 2
Символьные константы
(K&R 2.4.3)
# Все константы представляются 16-битовой величиной типа int.
# Turbo-C поддерживает ANSI-расширение, допускающее
шестнадцатеричное представление кодов символов.
Например, '\x1F' или '\x82'.
# Кроме того, поддерживается другое ANSI-расширение,
допускающее  ESC-последовательности.
Данный список ESC-последовательностей представляет собой дополнение списка,
приведенного в K&R.
.тм 3 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.
.зп 2
Константы с плавающей точкой
(K&R 2.4.4)
# Все константы, определенные как double,
представляют собой константы с плавающей точкой.
Однако, константа с плавающей точкой может иметь тип
float; необходимо добавлять суффикс F или f к ее значению.
.зп 2
Строки
(K&R 2.5)
# Turbo-C допускает многостроковые элементы
в символьных константах; строковая константа будет
представлять собой объединение элементов.
# Например,
.оф
main()
 {
     char *p;
     p="Данная программа - пример того, как Turbo-C"
       "будет автоматически\nосуществлять объединение"
       "строк в очень длинную строку;\n"
       "такая структура используется для большей"
       "наглядности программы.\n"
 }
.зп 2
Зависимость от машины
(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.
.зп 2
Преобразования
(K&R 6)
.зп 2
Char, int и enum
(K&R 6.1)
# Преобразование символьной константы к целому имеет результатом 16-битовое
значение. Преобразование символьного объекта (переменной) к
целочисленному объекту имеет результатом автоматическое
знаковое раширение, если вы сделали по умолчанию тип char
беззнаковым (используя при компиляции опцию -K).
Объекты типа signed char всегда  используют знаковое расширение;
объекты типа unsigned char всегда устанавливают старший бит в нуль,
когда преобразуются в int.
# Значения типа enum преобразуются в int без модификации;
аналогично тип int преобразуется в перечислимый тип.
.зп 2
Указатели
(K&R 6.4)
# Указатели, используемые программой, могут быть различных размеров,
в зависимости от используемой модели памяти.
Например, когда вы компилируете программу, используя специальную модель памяти,
адресуемые модификаторы (индексные регистры) (near, huge, far, _cs, _ds,
_ss, _es) могут не принимать во внимание размер указателя,
заданный данной моделью памяти.
# Указатель должен быть объявлен как указатель на некоторый
специальный тип, даже если данный тип - void (который в действительности
означает указатель на ничего). Однако, будучи объявлен, указатель
может указывать на объект любого другого типа.
Turbo-C позволяет переназначать указатели, но компилятор будет
предупреждать, что произошло переназначение указателя -
если указатель не был первоначально определен как
указатель на тип void. Однако указатели на типы данных не
могут быть преобразованы к указателям на типы функций, и наоборот.
.зп 2
Арифметические преобразования
(K&R 6.6)
# Преобразование операндов в арифметических выражениях
выполняется по следующим правилам:
.na
Любой не-integer и не-double тип преобразуется как
показано в таблице, приведенной ниже.
.na
Если какой-либо из операндов имеет тип double, другой операнд
тоже преобразуется в double.
.na
Если какой-либо из операндов имеет тип unsigned long, другой операнд
тоже преобразуется в unsigned long.
.na
Если какой-либо из операндов имеет тип unsigned, другой операнд
тоже преобразуется в unsigned.
.тм 4 Методы арифметических преобразований
------------------------------------------------------
                  Результат
Тип           преобразования          Метод
------------------------------------------------------
char               int              знаковый
unsigned char      int         нулевой старший байт
                                        (всегда)
signed char        int         знаковый (всегда)
short              int         если беззнаковый,
                                то беззнаковый int
enum               int         та же величина
float              double      мантисса дополняется 0
.зп 2
Операторы
(K&R 7.2)
# Turbo-C поддерживает унарный оператор +. Обычно
Turbo-C осуществляет перегруппировку выражений,
переупорядочивая коммутативные операторы (такие как * и двоичный +),
пытаясь создать выражения эффективные при компиляции.
Однако Turbo-C не будет переорганизовывать выражения с унарным оператором +.
Следовательно, вы можете контролировать вычисления с плавающей точкой,
т.е. отлавливать ошибки точности и переполнения, используя унарный оператор +,
и при этом не разбивая целое выражение на   отдельные выражения.
Например, Если a, b, c и f имеют тип float, выражение
# f=a++(b+c)
.пс 1
будет вычисляться следующим образом:  результат (b+c)
будет прибавлен к a.
.зп 2
Спецификации типов
(K&R 8.2)
# Turbo-C поддерживает следующие основные типы, не указанные в K&R.
.эб 1
unsigned char
.эб 1
unsigned short
.эб 1
unsigned long
.эб 1
long double
.эб 1
enumeration
.эб 1
viod
# Тип long double эквивалентен типу double.
.зп 2
Тип 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 - проверка типа не производится.
.зп 2
Тип void
# Turbo-C поддерживает тип void, определенный в ANSI-стандарте.
Данный тип используется для явного описания функций, не возвращающих значений.
Аналогично, пустой список параметров может
быть объявлен словом void.
Например,
.sw
void putmsg(void)
 {
        printf("Hello, world\n");
 }

main()
 {
        putmsg();
 }
# Можно преобразовывать выражение к типу void, для того чтобы явно указать, что
значение, возвращаемое функцией, игнорируется.
Например, если вы хотите приостановить выполнение программы до тех пор пока
пользователь не нажмет какую-либо клавишу, вы можете написать:
.sw
        (void) getch();
# Кроме того, можно объявить указатель на объект типа void.
Данный указатель не будет указателем на ничего; создастся указатель на
какой-то объект данных, тип которого нет необходимости определять.
Вы можете присваивать любой указатель указателю типа void, и обратно.
Однако вы не можете использовать оператор косвенной адресации (*),
т.к. используемый тип неопределен.
.зп 2
Знаковый модификатор
# Кроме указанных в K&R трех типов модификаторов -
long, short и unsigned - Turbo-C поддерживает еще три:
signed, const и vilatile (ANSI-стандарт).
# Модификатор signed явно указывает, что величина со знаком.
Данный модификатор используется преимущественно для документированности
и завершенности программ. Однако, если вы компилируете программу,
используя по умолчанию беззнаковый тип char (вместо знакового),
необходимо использовать модификатор signed, для того чтобы
определить переменную или функцию типа signed char.
Модификатор signed, использованный сам по себе, означает signed int,
также как unsigned означает unsigned int.
.зп 2
Модификатор const
# Модификатор const, как определено в ANSI-стандарте,
не допускает каких бы то ни было переопределений значения
константы  или других  косвенных действий,
таких как уменьшение или увеличение.
Указатель на тип const не может быть изменен, в отличии от самого
объекта, который он определяет.
.пр Модификатор const, используемый сам по себе, эквивалентен
const int.
Рассмотрим следующий примеры:
.sw
        const float pi          =3.1415926;
        const       maxint      =32767;
        const *char str         ="Hello, world";
# Приведенные ниже утверждения недопустимы:
.sw
        pi  = 3.0;              /* Присвоение значения
                                        константе */
        i   = maxint--;         /* Уменьшение константы */
        str = "Hi, there!";     /* Переназначение указателя */
.пр Однако, вызов функции strcpy(str,"Hi, there!") допустим,
т.к. в данном случае осуществляется посимвольное копирование строки
"Hi, there!" в ячейки памяти, определяемые str.
.зп 2
Модификатор volatile
# Модификатор
volatile
- почти полная противоположность const.
Он указывает, что объект может быть изменен; но не только непосредственно
вашей программой, но и также внешним воздействием, таким как
программа прерываний или порт ввода/вывода. Объявление
объекта как
volatile предупреждает компилятор, что не нужно делать предположений
 относительно
значения объекта, в то время как оцениваются выражения,
его содержащие, т.к. значение может (теоретически)
измениться в любой момент. Кроме  того, использование
данного модификатора не позволяет компилятору использовать
вместо переменных
регистровые переменные.
# Примеры:
.sw
        volatile int ticks;
        interrupt timer();
        {
                ticks++;
        }

        wait (int interval)
        {
                ticks=0;
                while(ticks, <=, >=)  работают правильно с указателями
типа huge; но не с указателями типа far.
.эб 1
Все арифметические операции над указателем huge воздействуют как на
адрес сегмента, так и на смещение (из-за нормализации);
при использовании far указателей - воздействие только на смещение.
.эб 1
Заданный указатель типа huge может быть увеличен в пределах
1Мб адресного пространства; указатели типа far будут при определенных
обстоятельствах циклически переходить на начало 64К сегмента.
.эб 1
При использовании указателей типа huge требуется дополнительное время,
т.к. программы нормализации должны вызываться после выполнения любой
арифметической операции над указателями.
.зп 2
Структуры и объединения
(K&R 8.5)
# Turbo-C обеспечивает следующие дополнительные возможности.
.зп 2
Выравнивание слов
#  Если при компиляции используется опция -a, Turbo-C
будет заполнять байтами структуру (или объединение) таким образом, как
требуется для выравнивания слов.
Обеспечивается следующее:
.эб 1
Структура будет начинаться с границы слова (четный адрес).
.эб 1
Любой член, имеющий не-char тип, будет иметь четное смещение от
начала структуры.
.эб 1
В конец  будет добавлен байт (если необходимо), для
гарантии того, что
структура содержит четное число байт.
.зп 2
Битовые поля
# Битовое поле может иметь тип либо signed, либо unsigned int и
может занимать от 1 до 16 битов. Битовые поля размещаются в направлении
от младших к старшим
битам в слове. Например, структура
.sw
        struct mystruct {
                int             i : 2;
                unsigned        j : 5;
                int               : 4;
                int             k : 1;
                unsigned        n : 4;
        } a, b, c;
.пс 1
обеспечивает следующее размещение:
.вп 10
.sw
 __________________________________________________
 |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.
.зп 2
Операторы
(K&R 9)
# Turbo-C выполняет все без исключения операторы, описанные в
K&R.
.зп 2
Определение внешних функций
(K&R 10.1)
# Описание extern, заданное внутри функции, имеет действие
в пределах данного блока.
Описание не будет распознаваться вне блока, в котором оно определено.
Однако, Turbo-C будет "запоминать" описания, для того чтобы
сравнивать их с последующими
описаниями тех же самых объектов.
# Turbo-C поддерживает дополнительные модификаторы функций, такие как
прототипы функций (ANSI-стандарт). Существует несколько собственных расширений
Turbo-C, например функции типа interrupt.
.зп 2
Модификаторы типа функции
(K&R 10.1.1)
# В дополнение к external и static, Turbo-C поддерживает
ряд модификаторов типа для описания функций: pascal, cdecl, interrupt,
near, far и huge.
.зп 3
Модификатор функции pascal
# Данный модификатор используется для функций (или указателей на функции),
которые используют Паскалевскую последовательность передачи параметров.
Это позволяет писать на языке C функции, которые могут быть
вызваны из программ, написанных на другом языке; аналогично,
наличие модификатора будет допускать обращение из C-программ,
к внешним подпрограммам, написанным на других языках. Имя функции преобразуется
к верхнему регистру, что необходимо для работы редактора связей.
.пр Использование опции -p будет приводить к тому, что все функции
(и указатели на эти функции) будут рассматриваться как если бы они
имели тип pascal.
Например, если вы объявили и откомпилировали следующую функцию:
.sw
        pascal putnums(unt i, int j, int k)
        {
           printf("And the answers are: %d, %d и %d\n",i,j,k);
        }
.пс 1
другая C-программа может затем подключить данную функцию при
работе редактора связей и обращаться к ней, используя описание:
.sw
        pascal putnums(int i, int j, int k);
        main()
        {
                putnum(1,4,9);
        }
# Функции типа pascal не могут иметь различное число аргументов,
как, например, функция printf.
По этой причине вы не можете использовать эллипсис (...)
(пропуск подразумеваемого аргумента) в определении функции
типа pascal.
.зп 3
Модификатор функции cdecl
# Данный модификатор аналогичен модификатору pascal; используется
с функциями или
указателями на функции, для того чтобы отменить
директиву компилятора -p и объявить функцию как
обычную C-функцию.
Например, если вы при компиляции программы установили опцию -p,
но хотите использовать printf, вы должны поступить следующим образом:
.sw
        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.
.зп 3
Модификатор функции interrupt
# Модификатор interrupt предназначен для использования с векторами прерываний
процессора 8086/8088.
Turbo-C будет компилировать функцию типа interrupt с дополнительным
входом и кодом завершения, так что регистры AX, BX, CX, DX, SI, DI, ES и DS
сохраняются.
Другие регистры: BP, SP, SS, CS и IP сохраняются как часть последовательности
C-вызова или часть самой обработки прерывания.
Рассмотрим пример стандартного определения функции типа interrupt.
.sw
        void interrupt myhandler()
        {
                . . .
        }
# Желательно объявлять функции прерываний как функции типа void.
Функции прерываний поддерживаются для всех моделей памяти.
Для всех моделей, исключая huge, в регистр DS заносится сегмент
данных программы. Для модели huge в DS заносится модульный сегмент
данных.
.зп 3
Прототипы функций
(K&R 10.1.2)
# В K&R допускается только объявление функции, состоящее из имени,
типа и пустых скобок.
Параметры (если они есть) объявляются только в определении непосредственно самой
функции.
# ANSI стандарт и Turbo-C допускают использование прототипов функций,
для того чтобы объявить функцию.
Существуют специальные описания, которые
включают информацию о параметрах функции.
Компилятор использует данную информацию для проверки
вызовов функций, а также для преобразования аргументов
к требующемуся типу.
Рассмотрим следующий фрагмент программы:
.sw
        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 передавались бы  параметры, не совпадающие по
размеру и содержанию с ожидаемыми.
Использование прототипов функций позволяет избежать ошибок.
# Описание функции
.sw
        f(void)
.пс 1
означает, что функция не имеет аргументов.
# В противном случае, в скобках указывается список параметров,
разделенных запятыми.
Объявление может быть сделано в форме
.па
func(int *, long);
.па
или в него могут быть включены идентификаторы
.па
func(int * count, long total);
# В обоих случаях, указанных выше, функция func
принимает два параметра:
указатель на тип int, названный count, и целую переменную total
типа long. Идентификатор, указанный в объявлении, используется
только в диагностическом сообщении, в случае возникновения
несоответствия типа параметров.
# Прототип функции обычно определяет функцию как функцию, принимающую
фиксированное число параметров. Для C-функций, которые принимают различное
число параметров (например, printf), пропотип функции может
заканчиваться многоточием (...),
например
.па
f(int *count, long total, ...)
# При такой форме прототипа фиксированные параметры
проверяются во время компиляции, а переменные параметры передаются,
как при отсутствии прототипа.
# Рассмотрим несколько примеров.
.sw
        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 на
                        строку; получает два параметра */

        int printf(char *format,...);  /* Функция возвращает
                        значение типа int, получая указатель
                        на фиксированный параметр типа char
                        и любое число дополнительных
                        параметров неизвестного типа */

        int (*fp)(int);  /* Указатель на функцию, возвращающую
                        значение типа int и получающую
                        единственный int параметр */
# Общие правила работы с модификаторами языка и формальными
параметрами в вызовах функций, как использующих протопиты, так и их
не использующих:
.na
Модификаторы языка для описания функций должны совпадать с модификаторами,
используемыми в объявлении функции, для всех обращений к функции.
.na
Функция может изменять значения формальных параметров, но
это не оказывает какого-либо воздействия на значения действительных
аргументов в вызывающей программе, за исключением функций прерывания.
# Если прототип функции не объявлен предварительно,
Turbo-C преобразует аргументы при обращении к функции согласно
правилам, описанным в разделе "Арифметические преобразования".
Если объявлен прототип, Turbo-C преобразует аргуметы к типу,
объявленному для параметров.
# Если прототип функции включает многоточие (...),
Turbo-C преобразует все заданные аргументы функции к аргументам, задаваемым
прототипом (до многоточия).
Компилтор будет расширять любые аргументы, заданные после
фиксированных параметров, по нормальным правилам для аргументов
функций без прототипов.
# Если есть прототип, число аргументов должно быть соответственным (за
исключением случая, когда в прототипе опущен какой-либо аргумент).
Типы должны быть совместимы только по размеру, для того чтобы корректно
производились преобразования типов. Вы всегда должны использовать
явные преобразования аргументов к типу, допустимому для прототипа функции.
# ПРИМЕР:
.оф
int strcmp(char *s1, char *s2);   /* Полный прототип */
int *strcpy();                    /* Нет прототипа */
int samp1(foat, int, ...);        /* Полный прототип */

samp2()
 {
        char *sx, *cp;
        double z;
        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-ех). В этом случае Turbo-C
теряет небольшое количество времени и генерит код для помещения
лишнего аргумента в стек. Это, однако, не является синтаксической ошибкой,
т.к. компилятор не знает о числе аргументов strcpy.
Такой вызов не допустим для других компилиторов.
# В 3-ем примере прототип требует, чтобы 1 аргумент для samp1 был
преобразован к float, а 2-ой - к int. Компилятор выдаст предупреждение
о возможной потере значимых цифр вследствие того, что при
преобразовании типа long к типу int отбрасываются верхние биты.
Вы можете избавиться от выдачи такого предупреждения, если
зададите явное преобразование к целому. Третий аргумент, q,
соответствует опущенному аргументу в прототипе. Он преобразуется
к типу double согласно обычному арифметическому преобразованию.
Весь вызов корректен.
# В 4 вызове снова встречается обращение к strcpy, но
число аргументов слишком мало. Это вызовет ошибку при выполнении
программы. Компилятор же ничего не сообщит (если даже число
параметров отличается от числа параметров в предыдущем
вызове той же функции), т.к. для strcpy нет прототипа функции.
# В 5 вызове для функции samp1 задано слишком мало аргументов.
Т.к. samp1 требует минимум 2 аргумента, этот оператор является ошибочным.
Компилятор выдаст сообщение о том, что в вызове не хватает аргументов.
.пр Если ваш прототип функции не соответствует действительному
определению функции, Turbo-C обнаружит это в том и только в том случае,
если это определение находится в том же файле, что и прототип.
Если вы создаете библиотеку программ с соответствующим сборником прототипов
(include-файлом), вы должны учитывать включение файла с прототипами
во время компиляции библиотеки, для того чтобы отловить любое
противоречие между прототипами и действительными определениями функций.
.зп 2
Правила видимости (K&R 11)
# Правила видимости - это правила, определяющие, в каких
частях текста программы может быть использована переменная в зависимости
от того, где и как она описана.
# Turbo-C разрешает более вольное обращение с неуникальными
идентификаторами, чем того требует K&R. Различают 4 класса идентификаторов:
# Имена, описываемые с помощью слова typedef, переменные,
члены перечисления должны быть уникальными внутри блока, в котором
они описаны. Идентификаторы, объявленные внешними, должны быть
уникальными среди переменных, описанных как внешние.
# Структура, объединение, признаки перечисления должны быть уникальными
внутри блока, в котором они описаны.
Признаки, описанные вне пределов какой-либо функции, должны быть
уникальны среди всех признаков, описанных как внешние.
# Имена структуры и члена объединения должны быть уникальны
в структуре или объединении, в которых они описаны.
Не существует никаких ограничений на тип или
смещение для членов с одинаковым именами в различных структурах.
# Операторы GOTO на метку должны использоваться лишь в той функции,
где объявлена данная метка. Метка, в свою очередь, должна быть
уникальна для функции, в которой она объявлена.
.зп 2
Команды управления трансляцией (R&K 12)
# Turbo-C поддерживает все управляющие команды, описанные в K&R.
Этими командами являются директивы препроцессора - строки
исходной программы, начинающиеся со знака #.
.зп 2
Замена лексем (K&R 12.1)
# Turbo-C выполняет все определения #define и #undef,
описанные в R&K, со следующими дополнениями:
# 1. Следующие идентификаторы не обязательно должны встречаться
в директивах #define и #undef:
#_STDC_
#_FILE_
#_LINE_
#_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 не осуществляет
подстановок макроаргументов внутри строк и символьных констант.
.зп 2
Включение файла (K&R 12.2)
# Turbo-C использует директиву так же, как описано в K&R,
но существуют некоторые дополнительные особенности:
Если препроцессор не нашел include-файл в каталоге, установленном
по умолчанию (преполагается, что вы используете форму
#include "filename"), тогда он ищет каталоги, заданные опцией
компилятора -I.
Если вы используете форму #include , тогда ищутся
только каталоги, заданные опцией -I.
(Каталоги, перечисляемые в меню по опции O/Environment/Include,
эквивалентны каталогам, заданным с помощью опции -I pathname
в командной строке.
# Вы можете задать имя пути #include, включающее граничные разделители,
используя макрорасширение. Если следующая строка после
ключевого слова начинается с идентификатора, препроцессор просматривает
текст для макроса. Однако, если строка заключена в кавычки
или в угольные скобки, Turbo-C не будет проверять ее для
запоминания макроса. Например,
# #define myinclude  "c:\tc\include\mystuff.h"
# #include myinclude
# #include "myinclude"
# 1-ый #include-оператор
заставит препроцессор просматривать C:\TC\INCLUDE\MYSTUFF.H, тогда как
2-ой вызовет просмотр MYINCLUDE.H в каталоге по умолчанию.
# Вы можете не использовать объединение литерных строк и вставку
лексем в макросе, который используется в операторе #include.
Макрорасширение должно генерить текст, который читается как
нормальная #include-директива.
.зп 2
Условная компиляция (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:
# #if defined(mysym) || defined(yoursym)
# Turbo-C (в отличие от ANSI) позволяет вам использовать
оператор sizeof в выражении для препроцессора:
.sw
     #if (sizeof(void *) ==2)
     #define SDATA
     #else
     #define LDATA
     #endif
.зп 2
Управление строками (K&R 12.4)
# Turbo-C поддерживает определение #line, данное в K&R.
.зп 2
Директива обработки ошибок (ANSI C 3.8.5)
# Turbo-C поддерживает директиву #error, которая упоминается (но не
определяется) в ANSI-стандарте. Ее формат:
# #error errmsg
# Если вы включите эту директиву условной компиляции
в файл с вашей исходной программой и условные тестовые файлы,
препроцессор будет считывать директиву #error и немедленно прерываться,
выдавая при этом следующее сообщение:
# Fatal:  filename  line#  Error directive:  errmsg
# Препроцессор просматривает текст для того, чтобы уничтожить
комментарии, но на экран выводит оставшийся текст без просмотра для
выявления макросов.
.зп 2
Директива PRAGMA (ANSI C 3.8.6)
# Turbo-C поддерживает директиву #pragma, которая (как и
#error),  неясно
определяется в ANSI-стандарте. Ее целью является  разрешить
специализированные директивы:
#  #pragma 
# С помощью  #pragma Turbo-C может определить любые директивы,
которые ему требуются, без вмешательства других компиляторов,
которые поддерживают #pragma. По-определению, если компилятор
не опознал имя директивы, он игнорирует директиву #pragma.
.зп 3
 #pragma inline
# Turbo-C распознает две директивы #pragma. Первая:
#  #pragma inline
# Эта директива эквивалентна опции компилятора -B.
Она сообщает компилятору о том, что в вашей программе присутствуют
ассемблеровские машинные команды. Наилучшее ее положение - в начале
файла, т.к. компилятор самоперезапускается с опцией -B сразу,
как только встретится #pragma inline. На самом деле, вы можете
опустить и опцию -B, и директиву #pragma inline, т.к. компилятор
все равно сомоперезапускается, как только встретит
asm-операторы; целью этой опции и директивы является экономия
времени компиляции.
.зп 3
 #pragma warn
# Другая #pragma-директива - это
#pragma warn
# Данная директива позволяет вам не принимать во внимание
специальную опцию командной строки -wxxx (опция включения
специальных предупредительных сообщений).
# Например,  если ваша исходная программа содержит директивы:
.sw
     #pragma warn +xxx
     #pragma warn -yyy
     #pragma warn .zzz
# то xxx включит выдачу предупредительных сообщений (если даже
в подменю O/C/Errors/ она была выключена); yyy выключит выдачу
сообщений; а zzz восстановит первоначальное значение, которое
было в начале компиляции файла.
# Окончательный список 3-буквенных аббревиатур и сообщений, которые
они включают и выключают, приведен в
Приложении 3 Ссылочного Руководства по Turbo-C.
.зп 2
Нулевая директива (ANSI C 3.7)
# Ради завершенности,
ANSI-стандарт и Turbo-C опознают пустую директиву, состоящую
из строки, содержащей просто знак #. Эта директива всегда игнорируется.
.зп 2
Встроенные макро-имена
# ANSI-стандарт требует 5 встроенных макросов. Turbo-C
применяет все 5. Отметим, что
каждый из них начинается и оканчивается
символом подчеркивания (__).
.ym _LINE_
Номер обрабатываемой строки исходной программы - десятичная константа.
Первая строка исходного файла определена как 1.
.ym _FILE_
Имя обрабатываемого исходного файла - литерная строка.
.am
Данное макроопределение
изменяется всякий раз, как компилятор обрабатывает
директиву #include или директиву #line, или когда
закончился #include-файл.
.ym _DATE_
Дата начала обработки текущего исходного файла - литерная строка.
.am
Каждое вхождение _DATE_ в заданный файл гарантирует одно значение,
независимо от того, как долго уже продолжается обработка.
Дата имеет формат mmmddyyyy, где mmm - месяц (Jan, Feb и т.д.),
dd - число текущего месяца (1...31; в 1-ой из двух позиций dd
ставится пробел, если число меньше 10), yyyy - год (1987, 1988 и т.д.).
.ym _TIME_
Время начала обработки текущего исходного файла - литерная строка.
.am
Каждое вхождение _TIME_ в заданный файл гарантирует одно значение,
независимо от того, как долго уже продолжается обработка.
Время имеет формат hh:mm:ss, где hh - час (00...23),
mm - минуты (00...59), ss - секунды (00...59).
.ym _STDC_
Константа, равная 1, если вы компилируете с флагом -a, который
устанавливает совместимость с ANSI-стандартом (ANSI keywords only ... ON);
иначе макроопределение не определено.
.зп 2
Встроенные макросы Turbo-C
# Препроцессор Turbo-C определяет различные дополнительные макросы.
Также, как для макросов, предписанных ANSI-стандартом,
каждый из них начинается и оканчивается
символом подчеркивания (__).
.ym _TURBOC_
Выдача номера текущей версии Turbo-C - шеснадцатеричная константа.
Версия 1.0 представляется как 0x0100; версия 1.2 - как 0x0102 и т.д.
.ym _PASCAL_
Определяет значение флага -p; устанавливается в целую константу,
равную 1, если используется флаг -p; иначе не определено.
.ym _MSDOS_
Целая константа, равная 1.
.ym _CDECL_
Определяет значение флага -p; устанавливается в целую константу,
равную 1, если флаг -p не используется; иначе не определено.
# Следующие 6 макросов зависят от выбранной для компиляции
модели памяти. Для любой компиляции определен может быть только
один из них; остальные (по-определению) не определены.
Например, если вы компилируете с маленькой моделью, определено _SMALL_,
а остальные - нет; поэтому директива #if defined(_SMALL_)
будет иметь значение true(верно), в то время как #if defined(_HUGE_)
(или любая другая) будет иметь значение fulse(ложно).
Действительное значение для любого определенного макроопределения
равно 1.
.ym _TINY_
Опции выбора  крошечной модели памяти.
.ym _SMALL_
Опции выбора  маленькой модели памяти.
.ym _MEDIUM_
Опции выбора средней модели памяти.
.ym _COMPACT_
Опции выбора компактной модели памяти.
.зп 1
Компилятор фирмы MICROSOFT MSC V4.0, V5.0
.зп 2
Различия между K&R и MSC
.тм 4 РАЗЛИЧИЯ МЕЖДУ K&R и MSC
---------------------------------------------------------------
Глава                   Отличия
в K&R
---------------------------------------------------------------
2.2     Идентификаторы распознаются по первым 31 символам.

2.3     asm и entry больше не ключевые слова. Новые ключевые
        слова: const, volatile, enum, signed, void.
        Слова cdecl, far, fortran, huge, near, pascal могут
        быть, а могут и не быть ключевыми словами.

2.4.1   В преобразовании типов шестнадцатеричные и восьмеричные
        константы всегда рассматриваются как беззнаковые целые.

2.4.3   Дополнительно введены символьные константы: '\V', '\A',
        '\Xчисло', где число представляет собой одну, две или
        три шестнадцатеричные цифры.
        Все символьные константы имеют тип int, и при
        преобразовании типов происходит расширение знака.

2.6     Тип short всегда занимает 16 бит, long - 32 бита.
        Тип int на процессорах 8086/8088, 80186, 80286 занимает
        16 бит, а на 80386 и 68000 - 32.

4       Тип char по умолчанию знаковый, хотя это умолчание можно
        изменить. При преобразовании типов у него происходит
        расширение знака. Поддерживаются два новых типа:
        unsigned char и unsigned long. Ключевые слова signed и
        unsigned могут употребляться как прилагательные к целым
        типам. Добавлены также типы enum и void.

6.4     Если разрешены ключевые слова near, far и huge, в
        программе могут встречаться указатели разной длины.
        Операции над ними могут вызывать их преобразование.

6.6     Преобразование типов по старшинству:
        1. Все float преобразуются в double.
        2. Если в выражении есть хотя бы один double, все
           преобразуется в double.
        3. Все char и short преобразуются в int.
        4. Все unsigned char и unsigned short преобразуются в
           unsigned int.
        5. Если в выражении есть хотя бы один unsigned long,
           все преобразуется в unsigned long.
        6. Если в выражении есть хотя бы один long, все
           преобразуется в long.
        7. Если в выражении есть хотя бы один unsigned int,
           все преобразуется в unsigned int.
        Допускаются преобразования между указателями разной
        длины в случае, если употребляются near, far и huge.

7.2     Всвязи с операцией sizeof можно заметить, что байт
        имеет 8 бит.

7.14    Есть присваивание структур.

8.2     Специфицированы ключевые слова enum и void.
        Ключевые слова signed и unsigned могут употребляться
        следующим образом:
        signed char
        signed short
        signed short int
        signed int
        signed long
        signed long int
        unsigned char
        unsigned short
        unsigned short int
        unsigned int
        unsigned long
        unsigned long int

8.4     Типы аргументов могут быть включены в список параметров
        функции для указания компилятору числа и типа аргументов
        при вызове.

8.5     Все битовые поля unsigned. Имена членов структур и
        объединений не обязательно должны отличаться от имен
        самих структур и объединений, а также от имен переменных
        Не существует взаимосвязи между членами двух разных
        структур.

8.6     Объединения инициализируются указанием значения первого
        члена.

9.7     Выражение оператора switch может иметь размер int или
        короче. Возможны выражения с типом enum. Каждое
        костантное выражение в case по типу должно совпадать с
        с выражением в switch.

10.1    Список  параметров  в  определении  функции  может
        заканчиваться конструкцией ',...' (в конце троеточие)
        или только  ', ' для  обозначения  переменного числа
        параметров у функции. Если список состоит только из
        этой конструкции,  то у функции  могут быть ноль или
        более параметров.

12      Между # и директивой препроцессора может быть любое
        число пробелов и табуляций.
        Добавлена директива #pragma.

12.3    Определена  конструкция  defined(идентификатор)  в
        операторе  #if,  так что  #ifdef и #ifndef можно не
        использовать.
        Добавлен #elif (else-if).

14.1    Структура  или  объединение  могут  присваиваться и
        передаваться функциям в качестве параметров.
        В выражении, включающем ->, выражение слева от стрелки
        должно быть типа той же структуры, в которой описан
        член справа от стрелки.

17      Перечисленные анахронизмы не распознаются.
.зп 2
Ограничения компилятора
# Во время трансляции компилятору нужно дисковое пространство для
временных файлов, равное по размерам примерно двум исходным файлам.
# Максимальная длина строки, включая нулевой символ '\0' не
должна превышать 512 байт.
# Максимальный размер констант зависит от их типа.
# Максимальная длина идентификатора 31 символ.
# Максимальное число уровней вложенности определений структур/объеденений - 5.
.зп 2
Ограничения препроцессора
# Максимальный размер макроопределения 512 байт
# Максимальное число аргументов в макро - 8.
# Максимальная длина аргументов - 256 байт.
# Максимальный уровень вложенности для дериктив типа #if, #ifdef, #ifndef - 32.
# Максимальный уровень вложенности включаемых файлов - 10.
.зп 1
Стандартные модели памяти компиляторов Turbo-C и MSC
# Turbo-C и Microsoft C (MSC) имеют пять общих моделей памяти.
# Для всех пяти моделей памяти справедливы следующие ограничения:
.na
Ни один исходный модуль не может генерить 64К или больше команд.
.na
Если не применяется огромная (huge) модель памяти, и элемент данных (например,
массив) не описан с помощью ключевого  слова huge (см. ниже),
он не может превышать 64К.
.ym Малая (small) модель
Включена по умолчанию. При этом программа формируется с одним
сегментом данных и одним сегментом команд (сегмент равен 64К).
Следовательно, программы в этой модели не могут превышать 128К.
По умолчанию в данной модели все указатели имеют тип 'near',
но можно вводить и другие ключевыми словами far и huge (см. ниже).
.ym Средняя (medium) модель
Программа формируется с несколькими сегментами команд и одним сегментом данных.
Обычно применяется для программ с большим размером команд и малым размером
данных, при этом каждый исходный модуль имеет свой собственный сегмент команд.
.ym Компактная (compact) модель
Программа формируется с несколькими сегментами данных и одним сегментом команд.
По умолчанию в этой модели все указатели на код имееют тип 'near',
а на данные - 'far'. Можно вводить другие указатели на код ключевым
словом 'far' и на данные ключевыми словами 'near' и 'huge' (см. ниже).
.ym Большая (large) модель
Программа формируется с несколькими сегментами команд и несколькими сегментами
данных. По умолчанию в этой модели элементы кода и данных имеют адреса типа
'far'. Можно вводить другие указатели на код ключевым словом 'near'
и на данные ключевыми словами 'near' и 'huge' (см. ниже).
.ym Огромная (huge) модель
Программа формируется с общими сегментами команд и данных. Таких сегментов
может быть сколько угодно.
# В этой модели снимается ограничение на размер элемента данных (например,
массива) в 64К, но остаются следующие ограничения сегментации:
.na
Одиночный элемент данных (например, элемент массива) не может быть более 64К.
.na
Для любого массива размером больше 128К все элементы должны иметь размер,
кратный 2.
# Так как результат оператора sizeof и разности двух указателей есть
величина типа int, а в случае больших элементов это может не соблюдаться,
MSC позволяет получать корректные значения следующим образом:
чтобы получить размер большого элемента оператором sizeof,
необходимо использовать следующую конструкцию:
# (long) sizeof (huge_item),
# где huge_item - требуемый элемент. Для получения разности двух
указателей на 'huge' элементы необходимо использовать следующую конструкцию:
# (long) (huge_ptr1 - huge_ptr2).
.зп 2
Модель памяти tiny
# Turbo-C имеет в дополнении к указанным выше еще одну модель
памяти - tiny.
Это самая малая модель памяти. Все четыре регистра
( CS, DS, SS, ES) содержат один и тот же адрес, поэтому
64К выделяются для хранения кода, данных и массивов.
Всегда используются указатели типа near.
Программы, использующие модель памяти tiny, могут быть
преобразованы к формату .COM.
.зп 2 Использование ключевых слов 'near', 'far' и 'huge'
# Один из неприятных моментов в использовании моделей памяти заключается
в том, что по различным причинам (например, для увеличения быстродействия)
приходится использовать указатели разного размера, а не только
определенного при данной модели памяти. Однако, MSC позволяет уладить это
с помощью использования ключевых слов near, far и huge.
Эти ключевые слова действительны только при работе с ОС MS DOS на
процессорах семейства 8086, и могут быть удалены с помощью ключа /ZA в MSC.
.зп 3 Ключевое слово near
# Элемент, на который ссылается указатель, резидентен в текущем сегменте
команд или в стандартном сегменте данных. Указателем является 16-битный
адрес данных или функции в коде. В адресной арифметике использует 16 бит.
.зп 3 Ключевое слово far
# Элемент, на который ссылается указатель, может располагаться где угодно,
не обязательно в текущем сегменте команд или стандартном сегменте данных.
Указателем является 32-битный адрес данных или функции в коде.
В адресной арифметике использует 16 бит.
.зп 3
Ключевое слово huge
# Элемент на который ссылается указатель может располагаться
в данных где угодно, не обязательно в стандартном сегменте.
Одиночный элемент данных (например, элемент массива) не может
иметь размер больше 64 Кб. Указателем является 32-битный адрес данных.
В адресной арифметике используется 32 бита.
# Стандартная С-библиотека, должна соответствовать модели памяти
Вашей программы: (малой (small) по умолчанию, компактной (compact),
средней (medium),  большой (large)).(XLIBC.LIB, где X - первая буква
названия модели памяти). Стандартная библиотека для большой модели
памяти может применяться также и для огромной (huge) модели.
В общем случае нельзя использовать 'far' и  'huge' функции библиотеки
при малой модели памяти.
# Для модификации элементов или указателей на элементы с помощью
ключевых слов near, far и huge необходимо помнить следующие правила:
.na
Ключевое слово модифицирует элемент или указатель непосредственно справа.
Например, char far* *p;  означает, что p это указатель на 'far' указатель
на char.
.na
Если непосредственно справа за ключевым словом идет идентификатор,
то оно определяет, где будет располагаться этот элемент, в стандартном
сегменте данных (near) или в других сегментах (far или huge).
Например: char far А; здесь А представляет собой элемент типа
char с адресом 'far'.
.na
Если непосредственно справа за ключевым словом идет указатель,
то оно определяет размер адреса: 16 бит (near) или  32 (huge или far).
Например, char far *p; здесь p рассматривается как 'far'
указатель (32 бита) на элемент типа char.
.оф
Примеры:
char a[3000]; /* малая (small) модель */
- а располагается в стандартом сегменте данных.

char far b[30000]; /* малая (small) модель  */
- b  может  располагаться  в  любом  сегменте  данных.
Если  имеется  мало таких массивов, дучше использовать
'far', чем большую модель памяти для ускорения доступа
к другим данным.

char a[3000]; /* большая (large) модель */
- даже  если  а  расположен  в  стандартном   сегменте
данных, доступ к нему будет осуществляться с использо-
ванием 32-битного указателя.

char near b[30000]; /* большая (large) модель  */
- доступ к b  будет  осуществляться  с  использованием
16-битного  указателя  (near),  что   будет  несколько
быстрее, чем в предыдущем случае.

char huge a[70000]; /* малая (small) модель  */
- а должен быть так описан, так как он занимает  более
64  Кб.  Использование  ключевого  слова  huge  вместо
огромной (huge)  модели  памяти позволяет обращаться к
другим  данным,  находящимся  в  стандартном  сегменте
гораздо быстрее по 'near' указателям.

char huge *pa; /* малая (small) модель */
- pa  может  применяться,  также, как а из предыдущего
примера. Вся адресная арифметикас ним (например, pa++)
использует 32 бита.

char *pa; /* малая (small) модель */
- 'near' указатель на char;

char far *pa; /* малая (small) модель */
- 'far' указатель на char;

char far* *pa; /* малая (small) модель */
- 'near' указатель на массив 'far' указателей на char;

char far* *pa; /* большая (large) модель */
- 'far' указатель на массив 'far' указателей на char

char far* near *pb; /* любая модель памяти */
- 'near' указатель на массив 'far' указателей на char

char far* far *pb; /* любая модель памяти */
- 'far' указатель на массив 'far' указателей на char
# Правила использования 'near' и 'far' для функций такие же, как
и для данных.
.na
Ключевое слово модифицирует функцию или указатель на функцию
непосредственно справа.
.na
Если непосредственно справа за ключевым словом идет функция,
то оно определяет, где будет располагаться этот элемент,
в текущем сегменте команд (near) или в других сегментах (far).
Например: char far fun(); здесь fun
представляет  собой функцию, вызываемую по 32-битному адресу и
возвращающую элемент типа char;
.na
Если непосредственно справа за ключевым словом идет указатель
на функцию, то оно определяет размер адреса: 16 бит (near) или 32 (far).
Например: char (far *pfun)(); здесь pfun рассматривается
как 'far' указатель (32 бита) на функцию, возвращающую элемент типа
char.
.na
Объявления функций должны соответствовать их определениям.
.na
Ключевое слово 'huge' не может применяться для функций.
# ПРИМЕРЫ:
.оф
char far fun();         /* малая (small) модель */
char far fun()  { /* ... */ }

- здесь fun - это функция, возвращающая элемент типа char,
и вызываемая по 32-битному адресу.


static char far* near fun();    /* большая (large) модель */
static char far* near fun() { /* ... */ }

- здесь fun это 'near' функция, возвращающая 'far'
указатель на char. Например, эта функция может использоваться
довольно часто только в том модуле, где она описана. Так как
она 'near', это будет происходить быстрее.


void far fun();         /* малая (small) модель */
void (far* pfun)() = fun;

- здесь pfun это 'far' указатель на функцию, не возвращающую
значения.


double far* (far fun)();  /* компактная (compact) модель */
double far* (far *pfun)() = fun;

- здесь pfun это 'far' указатель на функцию, возвращающую
'far' указатель на тип double.
# При использовании 'near', 'far' и 'huge' надо помнить, что указатели
меньшей, чем предусмотрено моделью памяти длины при использовании приводятся
к принятым в данной модели.

.зр Компиляторы языка Си ОС ДЕМОС и UNIX 2.9BSD, 4.2BSD
# В ОС Демос-2 (UNIX 2.9BSD) и Демос-32 (UNIX 4.2BSD) основными
компиляторами языка Си являются CC и PCC.  В основу первого положен компилятор,
разработанный одним из авторов языка Си Денисом Ричи. Язык этого компилятора
полностью соответствует описанному в K&R. Второй компилятор - это так назывемый
"мобильный" компилятор языка Си, разработанный У. Джонсоном. Язык, реализованный
этим компилятором, не отличается от языка, описанного в K&R. Следует иметь ввиду
что на основе этого компилятора сделан верификатор программ LINT, поэтому
этот компилятор гораздо строже проводит контроль типов данных и выдает гораздо
больше предупреждений о возможной немобильности программ.
.зп 1
Некоторые особенности написания программ на языке Си в ОС Демос-2
.na
недопустимы вложенные комментарии: /*.../*...*/...*/
.na
странные приоритеты: А&1==0 поймет как: А & (1==0)
.na
неизвестен момент выполнения операции ++: B = (А++) + (А++);
.na
можно описать одинаковые внешние имена в разных файлах - будет 1 ячейка
.na
имена только 7 (8) букв, различия после 7 букв игнорирует
.na
case - работают не как альтернативы, а как метки
.na
указатель != целому, гарантировано только 0==null, да и то не всегда
.na
длинные символьные константы А='АB' зависят от порядка байт в слове
.na
неизвестен порядок вычисления B: F(G(),K()) и А=F()+G()
.na
можно обращаться к функции с неправильным числом аргументов
.na
нельзя применить & к register переменной
.na
об'екты в памяти идут не подряд (не в порядке описания)
.na
неизвестно расположение байт внутри слова (nuxi-проблема)
.na
неизвестен порядок распределения битовых полей внутри слова
.na
в инициализаторах надо указывать тип констант
.na
могут быть одинаковые имена переменных в блоке и вне его
.na
лучше не C&0377 A (unsigned)C
.na
значащие пробелы: A =-B и A = -B
.na
константа 40000 будет взята как unsigned, а не long
.na
допустимы как '"' так и "'" конструкция
.na
путают: putc('A') и putc("A")
.na
можно: \1 \01 \001, но неоднозначно: "\12345"
.na
на конце строки должен быть \, а не \(пробелы)
.na
char не целое: 0377 != '\0377'
.na
для русских букв неверно: 'A' < 'Я'
.na
вся арифметика может идти в double, только хранение в float
.na
массив != указатель - нельзя: char A[5],*P; A=P; можно: P=A;
.na
имя функции без скобок - законное выражение(!?): exit(0); и exit;
.na
можно возвращать только указатели на static
.na
нельзя написать рекурсивный кластер
.na
++++А незаконно (А - L=значение, ++А - нет), даже ++(++А)
.na
-А для unsigned дает 2**N-А
.na
только: указатель+/-целое и указатель-указатель, иначе - чушь
.na
указатель & (^1) масштабируется
.na
if( A < B < C )  даст совсем не то, что задумано
.na
использование запятой if'ax и функциях: F(A,(B,C),D)
.na
можно сделать модуль без функций в нем - только данные
.na
массивы без границ полностью эквивалентны указателям: char P[];
.na
многомерный массив без границ - можно: A[] [20], нельзя: A[] []
.na
можно одинаковые имена у переменных, структур и их полей
.na
никак нельзя инициализировать union'ы и битовые поля
.na
при передаче управления внутрь блока по метке нет инициализации
.na
двусмысленность: if(...)...if(...)...else...;
.na
extern и не extern можно смешивать
.na
static переменные и функции недоступны из других файлов
.na
 #define...; - типичная ошибка
.na
#defin'ы можно писать посреди с-конструкций
.na
нельзя: #define A (...)... - недопустим пробел
.na
конструкция целое->поле непереносима, но применяется в драйверах
.na
указатель на функцию можно писать без &: exit;
.na
можно писать выражение без присваивания: A+B;
.na
преобразование указателей: (double*)malloc(...) - не будет выравнивания !!
.na
непереносимы длинные символьные константы: 'AB' 'ABC'...
.na
структуры возвращаются из функций нереентерабельно, как указатели
.na
можно A=B для переменных и структур, нельзя для массивов
.na
если: unsigned A,B,C;  то неэквивалентно: A-C<B и A<B+C
.зр Компилятор языка Си ОС XENIX
.тм 4 РАЗЛИЧИЯ МЕЖДУ K&R И КОМПИЛЯТОРОМ СИ ОС XENIX
---------------------------------------------------------------
Глава                   Отличия
в K&R
---------------------------------------------------------------
2.2     Идентификаторы распознаются по первым 31 символам.

2.3     asm и entry больше не ключевые слова. Новые ключевые
        слова: const, enum, void.
        Слова far, fortran, huge, near, pascal могут
        быть, а могут и не быть ключевыми словами.

2.4.1   В преобразовании типов шестнадцатеричные и восьмеричные
        константы всегда рассматриваются как беззнаковые целые.

2.4.3   Дополнительно введены символьные константы: '\V', '\A',
        '\Xчисло', где число представляет собой одну, две или
        три шестнадцатеричные цифры.
        Все символьные константы имеют тип int, и при
        преобразовании типов происходит расширение знака.

2.6     Тип short всегда занимает 16 бит, long - 32 бита.
        Тип int на процессорах 8086/8088, 80186, 80286 занимает
        16 бит, а на 80386 и 68000 - 32.

4       Тип char знаковый. При преобразовании типов у
        него происходит расширение знака. Поддерживаются
        два новых типа: unsigned char и unsigned long.
        Добавлены типы enum (перечислимый) и void (пустой).

6.4     Если разрешены ключевые слова near, far и huge, в
        программе могут встречаться указатели разной длины.
        Операции над ними могут вызывать их преобразование.

6.5     Ключевое слово unsigned может употребляться как
        прилагательное к целым  типам (int, long, short
        и char). Когда используется просто слово unsigned,
        то подрузамевается unsigned int.

6.6     Преобразование типов по старшинству:
        1. Все float преобразуются в double.
        2. Если в выражении есть хотя бы один double, все
           преобразуется в double.
        3. Все char и short преобразуются в int.
        4. Все unsigned char и unsigned short преобразуются в
           unsigned int.
        5. Если в выражении есть хотя бы один unsigned long,
           все преобразуется в unsigned long.
        6. Если в выражении есть хотя бы один long, все
           преобразуется в long.
        7. Если в выражении есть хотя бы один unsigned int,
           все преобразуется в unsigned int.
        Допускаются преобразования между указателями разной
        длины в случае, если употребляются near, far и huge.

7.2     Всвязи с операцией sizeof можно заметить, что байт
        имеет 8 бит.

7.14    Есть присваивание структур.

8.2     Специфицированы ключевые слова enum и void.
        Ключевое слово unsigned может употребляться
        следующим образом:
        unsigned char
        unsigned short
        unsigned short int
        unsigned int
        unsigned long
        unsigned long int

8.4     Типы аргументов могут быть включены в список параметров
        функции для указания компилятору числа и типа аргументов
        при вызове.

8.5     Все битовые поля unsigned. Имена членов структур и
        объединений не обязательно должны отличаться от имен
        самих структур и объединений, а также от имен переменных
        Не существует взаимосвязи между членами двух разных
        структур.

8.6     Объединения инициализируются указанием значения первого
        члена.

9.7     Выражение оператора switch может иметь размер int или
        короче. Возможны выражения с типом enum. Каждое
        костантное выражение в case по типу должно совпадать с
        с выражением в switch.

12      Между # и директивой препроцессора может быть любое
        число пробелов и табуляций.
        Добавлена директива #pragma.

12.3    Определена  конструкция  #ша defined(идентификатор)  в
        операторе  #if,  так что  #ifdef и #ifndef можно не
        использовать.
        Добавлен #elif (else-if).

14.1    Структура  или  объединение  могут  присваиваться и
        передаваться функциям в качестве параметров.
        В выражении, включающем ->, выражение слева от стрелки
        должно быть типа той же структуры, в которой описан
        член справа от стрелки.

17      Перечисленные анахронизмы не распознаются.
# Возможно использование тех же моделей памяти, что и в MSC.
Для создания программ, выполняемых под управлением MS-DOS,
существует опция компилятора -dos.

.зр Компилятор языка СИ ОС AIX
# Операционныя  ситема AIX представляет собой вариант ОС UNIX SYSTEM V,
с некоторыми добавлениями из OC UNIX 4.2BSD, реализованная фирмой IBM
для своей ЭВМ IBM RT PC (IBM 6150).
# В ОС AIX имеется 4 вида компилятора языка Си: СС, FCC, VCC, SCC.
Основным компилятором является компилятор СС. Остальные компиляторы используются для специальных приложений.
(FCC - для получения программ, работающих с аппаратным ускорителем плавающей точки;
VCC - для получения объектных файлов в формате VRM, SCC - для получения
stand-alone-оновских программ.
# По формату вызова компилятор СС практически не отличается от
аналогичного компилятора ОС Демос-2. Состав библиотеки стандартных функций
практически не отличается от библиотеки стандартных функций ОС ДЕМОС-2.
При написании экранных программ, следует иметь ввиду, что файла /etc/termcap
в стандартной поставке ОС AIX нет, хотя имеется библиотека CURSES,
аналогичная этим же библиотекам ОС ДЕМОС-2 и ОС XENIX.
На ЭВМ IBM RT PC
реализованы следующие скалярные типы данных:
.тм 3 Размер скалярных типов данных ЭВМ IBM RT PC
{
3
$ 8 Тип
$ 12 Размер
$ 20 Начальная граница
&
@ char
@ 8 разрадов
@ граница байта
&
@ short
@ 16 разрядов
@ полуслово
&
@ int
@ 32 разряда
@ слово
&
@ long
@ 32 разряда
@ слово
&
@ float
@ 32 разряда
@ слово
&
@ double
@ 64 разряда
@ слово
}
# Синтаксис реализованного языка Си практически не отличается от
описанного в K&R. Синтаксис языков YACC и LEX аналогичен
реализациям ОС Демос-2.
.зр Компилятор языка СИ для HP9000
# В этом разделе описаны машинно-зависимые особенности реализации языка Си
на ЭВМ HP 9000 (далее по тексту
HP-C).
# В
HP-C
реализованы следующие скалярные типы данных:
.тм 3 Размер скалярных типов данных ЭВМ HP9000
{
3
$ 8 Тип
$ 12 Размер
$ 20 Начальная граница
&
@ char
@ 8 разрадов
@ граница байта
&
@ short
@ 16 разрядов
@ полуслово
&
@ int
@ 32 разряда
@ слово
&
@ long
@ 32 разряда
@ слово
&
@ float
@ 32 разряда
@ слово
&
@ double
@ 64 разряда
@ слово
}
# Тип char имеет знаковое расширение (как на СМ-4).
Префикс register перед описанием переменной игнорируется, так как
ЭВМ HP9000 имеет стековую архитектуру. Переполнение целых не вызывает
ошибки, а деление на 0 фиксируется как ошибка. Разряды в полях
нумеруются слева направо.
# В
HP-C имеются следующие ограничения:
.эб 1
длина идентификатора до 16 литер (внешнего - до 15 литер);
.эб 1
область под переменные процедуры и область под параметры вызова не
превосходит каждая 2**19 (2 в 19 степени) байтов;
.эб 1
код ветвящейся конструкции не превосходит 2**18 байтов;
.эб 1
функция не может возвращать структуру, большую чем 2**24 байта;
.эб 1
в одну компиляцию допустимо включать не более 255 процедур;
.эб 1
С-компилятор порождает не более 32767 строк ассемблерного кода;
.эб 1
под глобальные скалярные данные (включая статические переменные)
отводится не более 2**19 байтов.
# Режим компилятора -v позволяет наблюдать за процессом компиляции.
Ошибки периода ассемблирования помещаются в файл /tmp/ctm3x.
# При переносе С-программ на HP9000 с других ЭВМ необходимо учитывать
следующее:
.эб 1
на HP9000 отсутствует пересылка байтов;
.эб 1
разименование нулевого имени как для чтения, так и для записи порождает
ошибку исполнения (тогда как на других ЭВМ при чтении выдается 0);
.эб 1
следует остерегаться абсолютной адресации, т.к. аппартная адресация
на HP9000 отличается от других ЭВМ;
.эб 1
хотя стек располагается по возрастанию адресов, но параметры загружаются
в стек по убыванию адресов, т.е. при использовании имени на список
параметров необходимо имя пошагово уменьшать.
.зр Советы по написанию мобильных программ
.зп 1
Мобильность программ
# Программа мобильна, если она может быть успешно откомпилирована и
выполнена на различных ЭВМ без переделки. Существует несколько способов написания
мобильных программ. Первый - избегать. присущие языку не иобильные особенности.
Второй - избегать немобильного взаимодействия с окружением, таким
как ввод/вывод на нестандартные устройства. Например, программы не должны
содержать внутри себя полные имена файлов, за исключением общих во всех
системах (таких как /etc/passwd).
# Файлы требуемые во время компиляциии (т.е. include files) также могут быь
не мобильными, так не все они могут быть на разных машинах.
В некоторых случаях include-файлы содержат машинные параметры, которые могут
использованы для создания исходных мобильных программ.
.зп 1
Аппаратное обеспечение
# Различия в аппаратной конфигурации используемых машин и различия
в соответствующих С-компиляторах вызывают большое количество проблем
по переносимости. Данный подраздел посвящен перечислению таких общих
проблем переносимости для систем XENIX.
.зп 2
Длина байта
# По определению, тип данных char в C должен быть достаточно большим для
хранения в виде положительного целого любого члена множества машинных
символов. Для машин, описанных в данном приложении, размер char равен
8-битному байту.
.зп 2
Длина слова
# В С размеры основных типов данных для заданной реализации формально не
определены. Таким образом, они обычно следуют наиболее естественному
размеру для используемой машины. С уверенностью можно предположить,
что short не будет длиннее, чем long. Кроме этого ничего с уверенностью
сказать нельзя. Например, на некоторых машинах short по длине совпадает
с int, тогда как для других по длине совпадают long и int.
# Программы, для которых необходимо знать размер частного типа данных,
должны по возможности избегать машинно-зависимых констант.
Такая информация обычно может быть написана достаточно переносимым способом.
Например, максимальное положительное целое (для двух комплектов машин)
может быть получено следующим образом:
# #define MAXPOS ((int)(((unsigned)-1)>>1))
# Это предпочтительней, чем, например, следующее:
.оф
        #ifdef PDP11
        #define MAXPOS 32767
        #else
        ...
        #endif

# Для определения числа байтов в int используйте лучше "sizeof(int)",
чем 2, 4 или какие-то другие непереносимые константы.
.зп 2
Выравнивание при хранении
# Язык С не определяет частной схемы для хранения элементов данных
относительно один другого, или для хранения элементов структур или
объединений внутри структуры или объединения.
# Некоторые CPU, такие как PDP-11 и M68000, требуют, чтобы типы данных
длиннее одного байта были выравнены по одинаковым границам адресов байтов.
Другие, такие как 8086 и VAX-11, не имеют таких ограничений по аппаратуре.
Однако,  даже на этих машинах большинство компиляторов генерирует код,
который выравнивает слова, структуры, массивы и длинные слова по
равным адресам или равным длинным адресам. Таким образом, на VAX-11
следующая последовательность кода даст 8, хотя аппаратура VAX позволяет
осуществить доступ к int (4-байтному слову) с любого начального
физического адреса:
.оф
        struct s_tag {
                char c;
                int i;
        };
        printf("%d\n",sizeof(s_tag));

# Это изменение в хранении данных в основном подразумевает,
что данные, к которым осуществляется доступ как к непростым типам данных,
являются непереносимыми, и код, который получает преимущества от
архитектуры частной машины, также непереносим.
# Таким образом, объединения, содержащие структуры, являются непереносимыми,
если объединение используется для осуществления доступа к одним и тем же данным
различными способами. Объединения могут быть переносимы, если
они используются для размещения различных данных в одном и том же
пространстве в различные моменты времени. Например, если следующее объединение
будет использоваться для получения 4 байт из длинного слова, код не будет
перносим:
.оф
        union {
                char c[4];
                long lw;
        }u;

# Оператор sizeof должен всегда использоваться при чтении и записи структур:
.оф
        struct s_tag st;
        ...
        write(fd,&st,sizeof(st));

# Это обеспечит переносимость исходного кода. Это не позволит создать
переносимый файл данных. Переносимость данных будет рассмотрена в одном из
последующих подразделов.
# Отметим, что оператор sizeof возвращает число байт, какое объект будет
занимать в массиве. Таким образом, на машинах, где структуры всегда
выравнены по границе начала слова в памяти, оператор sizeof будет включать
необходимое дополнение до нее в возвращаемое значение, даже в том случае,
если дополнение встретилось после всех полезных данных в структуре.
Это случается независимо от того, является или нет аргумент действительно
элементом массива.
.зп 2
Порядок байтов в слове
# Изменения в порядке байтов в слове воздействует на переносимость данных
больше, чем переносимость исходного кода. Любая программа, которая
использует внутренний порядок байтов в слове, не переносима.
Например, в некоторых системах существует include-файл misc.h, который
содержит следующее объявление структуры:
.sw
        /*
         * Структура для доступа
         * к целому в байтах
         */
        struct {
                char lobyte;
                char hibyte;
        };

# С определенными менее ограниченными компиляторами эта структура могла бы
использоваться для доступа к старшему и младшему по порядку байтам по
отдельности от целого числа, способ доступа при этом препятствовал бы
переносимости. Правильный путь для выполнения этой задачи заключается
в использовании маски и операций сдвига для выделения нужного байта:
.оф
        #define LOBYTE(i) (i&0xff)
        #define HIBYTE(i) ((i>>8)&0xff)

# Отметим, что даже эта операция подходит лишь для тех машин, у которых int
занимает два байта.
# Одним из результатов проблемы порядка байтов является то, что следующая
последовательность кода не всегда будет выполняться должным образом:
.оф
        int c=0;

        read(fd,&c,1);

# На машинах, где младший по порядку байт хранится первым, значение c
будет равно считанному значению байта. На других машинах считываемый байт
отличен от младшего по порядку байта, и значение с
будет различным.
.зп 2
Битовые поля
# Битовые поля применяются не во всех С-компиляторах. Там, где они есть,
поля не могут быть чем int,  и поля не могут перекрывать границу целого (int).
При необходимости компилитор пропускает промежутки и переходит к следующей
границе целого (int).
# Язык С не дает гарантий назначаются ли поля в int слева направо, либо
справа налево. Таким образом, пока битовые поля могут быть использованы
для хранения флагов и других малых элементов данных, их использование
в объединениях для анализа битов из различных данных определенно не переносимо.
# Для получения переносимости отдельное поле не должно превышать 16 бит.
.зп 2
Указатели
# Язык С щедр на допуски для манипуляций с указателями. Программа lint,
в частности, используется для обнаружения спорных присвоений и сравнений
указателей, которые некоторыми компиляторами могут быть истолкованы по-разному.
# Всегда непереносимым является использование указателей с применением
приведения типов при присвоении одного указателя другому, если указатели
принадлежат различным типам данных.  При этом почти всегда делаются
предположения о внутреннем порядке байтов и формате типов данных, что и
вызывает непереносимомость. В следующем фрагменте порядок байтов в данном
массиве не переносим:
.оф
        char c[4];
        long *lp;

        lp = (long*)&c[0];
        *lp = 0x12345678L;

# Программа lint выдаст предупредительные сообщения при таком использовании
указателей. Код, подобный приведенному выше, очень редко бывает действительно
оправдан или правилен. Он приемлем, однако, при использовании функции malloc
для для захвата пространства под переменные, которые не имеют тип char.
Программа объявляется типом char*, и возвращаемое значение приводится к типу,
который должен храниться в захваченной памяти. Если этот тип не char*,
то lint выдаст предупреждение, касающееся неправильного преобразования
типов. К тому же функция malloc написана так, чтобы всегда возвращать
начальный адрес, удобный для хранения всех типов данных. Lint не знает этого,
поэтому она дает также предупреждение о проблемах возможного выравнивания
данных. В следующем примере malloc используется для получения памяти под
массив из 50 целых чисел:
.оф
        extern char *malloc();
        int *ip;

        ip = (int*)malloc(50*sizeof(int));

# Этот пример вызовет предупредительное сообщение программы lint.
# Руководство по языку С XENIX утверждает, что указатель может быть назначен
(или приведен к типу) целого, большего, чем необходимо для его хранения.
Заметим, что размер типа int зависит от данной машины и реализации.
Этот тип будет long на одних машинах и short - на других. Обычно, не
полагайтесь, что:
# sizeof(char*) == sizeof(int)
# В большинстве реализаций значение нулевого указателя NULL определено как
целое значение 0. Это может привести к проблеме для функций, которые
ожидают аргументов-указателей длиннее, чем целые числа. Для переносимости кода
при передаче значения NULL правильного размера всегда используйте:
# func((char*)NULL);
.зп 2
Адресное пространство
# Адресное пространство, доступное для программ, работающих  под управлением
системы XENIX, значительно различается от системы к системе. Для малых
PDP-11 может быть доступно лишь 64 Кбайт для сочетания программы и данных.
Большие PDP-11 и некоторые 16-битные микропроцессоры допускают 64 Кбайт
для данных и 64 Кбайт для текста программы. Другие машины могут допускать
значительно больший текст, а также возможно большие данные.
# Большие программы или программы, которые требуют большой области
для данных, могут иметь проблемы по переносимости на малые машины.
.зп 2
Множество символов
# Язык С не требует использования множества символов ASCII. Фактически
единственным требование к  множеству символов является требование,
чтобы символы  подходили под тип данных char, и чтобы все символы
имели положительные значения.
# Во множестве символов ASCII все символы имеют значения между 0 и 127.
Таким образом, они все могут быть представлены 7 битами, и на 8-битной-на-байт
машине все они положительны, тогда как char интерпретируется как
signed (знаковый) или unsigned (беззнаковый).
# Существует множество макросов, определенных в XENIX(е) в заголовке
файла /usr/include/ctype.h, которые должны использоваться для большинства
проверок на принадлежность символа к некоторой
группе символов. Они обеспечивают изоляцию от внутренней
структуры множества символов и в большинстве случаев их имена более
значимы, нежели эквивалентная строка сравнения в тексте программы. Сравните:
# if(isupper(c))
# с
# if((c>='A')&&(c<='Z')).
# Для некоторых из этих макросов, таких, например, как проверка на
шестнадцатеричное число, эффект от использования даже больше.
Кроме того, применение этих макросов делает код более эффективным,
нежели явная проверка с помощью оператора if.
.зп 1
Различия в компиляторах
# Существует несколько С-компиляторов, работающих под управлением XENIX(a).
Для ситемы PDP-11 это компилятор "Ritchie". Также, для 11 и большинства других
систем существует Переносимый С Компилятор.
.зп 2
Знаковый и беззнаковый символьный тип
# В текущее состояние проблемы "знакового против беззнакового" символьного типа
(char) лучше всего описать как неудовлетворительное.
# Проблема знакового расширения представляет собой серьезное препятствие
для написания переносимого С, и в настоящее время наилучшим ее решением
является написание "оборонительного" кода, который не основывается на
особенностях частной реализации.
.зп 2
Операции сдвига
# Оператор сдвига влево "<<" сдвигает свой операнд на некоторое число
бит влево, заполняя вакантные биты нулями. Это так называемый логический сдвиг.
Оператор сдвига вправо ">>"
выполняет операцию логического сдвига по отношению к беззнаковой величине.
Если применить его по отношению к знаковой величине, освободившиеся
биты могут быть заполнены нулями (логический сдвиг) или знаковыми битами
(арифметический сдвиг). Решение зависит от реализации, и код,
использующий сведения о частной реализации, является не переносимым.
# Компиляторы PDP-11 используют арифметический правый сдвиг.
Чтобы избежать знокового расширения, необходимо выполнить сдвиг и
наложить в качестве  маски соответствующее число, имеющее больший порядок бит:
# char c;
# c = (c>>3)&0x1f;
# Избежать знакового расширения можно также с помощью использования
оператора деления:
# char c;
# c = c/8;
.зп 2
Длина идентификатора
# Использование длинных обозначений и имен идентификаторов
вызовет проблемы переносимости для некоторых компиляторов. Для того, чтобы
эти проблемы избежать, программа должна хранить следующие обозначения такими
короткими, какими только возможно:
.оф
        Обозначения для препроцессора С
        Локальные обозначения С
        Внешние обозначения С

# Используемый редактор связей может также наложить на число уникальных
символов среди внешних обозначений С.
# Обозначения, различающиеся в первых 6 символах, уникальны для большинства
препроцессоров языка С.
# В некоторых не XENIX(овских) реализациях С заглавные и строчные буквы
в идентификаторах не различаются.
.зп 2
Регистровые переменные
# Номер и тип регистровых переменных в функции зависит от аппаратного
обеспечения и компилятора. Излишние или ущербные объявления регистра
интерпретируются как нерегистровые объявления и не вызовут проблем по
переносимости.
# Для PDP-11 значимыми являются до трех объявлений регистров, и они должны
иметь типы int, char или pointer. Тогда как другие машины и компиляторы
могут поддерживать объявления вида:
# register unsigned  short
но на такую вещь нельзя полагаться.
# Т. к. компилятор игнорирует лишнюю переменную регистрового типа,
наиболее важные переменные регистрового типа должны объявляться в первую
очередь. Таким образом, если какая-либо игнорируется, это будет
наименее важная из них.
.зп 2
Преобразование типов
# Язык С имеет несколько правил для недопускающего
двусмысленного толкования (точные) преобразования типов;
также допускаются явные преобразования типов с помощью приведения типов.
Наиболее общей проблемой переносимости при точном преобразовании типов
является неожидаемое знаковое расширение. Это потенциальная проблема
возникает всякий раз как какое-то значение типа char сравнивается
с int. Например:
.оф
        char c;

        if(c==0x80)
        ...

.пс 0
не будет оценено верно на машине со знаковым расширением, т.к.
расширение знака для с происходит перед  сравнением с 0x80, имеющим тип int.
# Единственное безопасное сравнение между типами char и int выглядит
следующим образом:
.оф
        char c;

        if(c=='x')
        ...

# Такая запись надежна, т.к. С гарантирует, что все символы положительны.
Использование машинных восьмеричных констант подвержено знаковому расширению.
Например, следующая программа печатает на PDP-11 "ff80":
.sw
        main()
        {
                printf("%x\n",'\200');
        }

# Преобразование типов также имеет место при передаче аргументов функциям.
Типы char и short становятся int. Машины с знаковым расширением char
могут преподносить сюрпризы. Например, следующая программа даст на
некоторых машинах -128:
.sw
        char c = 128;
        printf("%d\n",c);

# Это происходит потому, что с преобразуется к int перед передачей
в функцию. Сама функция не имеет представления о первоначальном типе
аргумента, и ожидает получить int. Правильный путь управления такой
ситуацией - это защититься при написании текста, допуская возможность
знакового расширения:
.sw
        char c=128;
        printf("%d\n",c&0xff);

.зп 2
Функции с переменным числом аргументов
# Функции с переменным числом аргументов представляют частную проблему
переносимости, если типы аргументов также являются переменными.
В этих случаях код зависит от размера переменных типов данных.
# В XENIX(e) существует include-файл /usr/include/varargs.h,
который содержит макросы, используемые в функциях с переменными
аргументами для доступа к аргументам способом, сохраняющим переносимость:
.sw
        typed char *va_list;
        #define va_dcl int va_alist;
        #define va_start(list) list=(char*)&va_alist
        #define va_end(list)
        #define va_arg(list,mode)
                ((mode*)(list+=sizeof(mode)))[-1]

# Макроопределение va_end сейчас не требуется. Использование остальных
макросов будет показано на примерах библиотечной программы fprintf.
Она имеет первый аргумент типа FILE*, и второй аргумент типа char*.
Тип и номер последующих аргументов во время компиляции не известен.
Они определяются во время выполнения содержимым управляющей строки (2-ым
аргументом).
# Первые несколько строк в программе fprintf для объявления аргументов и
нахождения выходного файла и адреса управляющей строки выглядят так:
.sw
 #include 
 #include 

 int
 fprintf(va_alist)
 va_dcl
 {
        va_list ap;  /* указатель на список аргументов */
        char *format;
        FILE *fp;

        va_start(ap);  /* инициализация указателя на аргументы */
        fp = va_arg(ap,FILE*);
        format=va_arg(ap,char*);

        ...

 }
# Заметим, что всего лишь один аргумент заявлен для fprintf. Этот аргумент
объявляется с помощью макроопределения va_dcl типа int,
хотя его действительный тип во время компиляции не известен.
Указатель аргументов ap инициализируется с помощью va_start (устанавливается
на адрес первого аргумента). Последовательные аргументы могут быть вынуты
из стека постольку, поскольку их тип определяется  с помощью
макроопределения va_arg. Оно имеет тип своего второго аргумента;
оно управляет удалением данных из стека и величиной увеличения указателя
аргументов ap. В fprintf единожды находится упарвляющая строка,
известны типы последующих аргументов, и к ним может быть последовательно
осуществлен доступ с помощью повторных вызовов va_arg(). Например,
аргументы типа double, int* и short можно восстановить следующим
образом:
.sw
        double dint;
        int *ip;
        short s;

        dint = va_arg(ap,double);
        ip = va_arg(ap,int*);
        s = va_arg(ap,short);

# Использование этих макросов делает код более переносимым, хотя
и предполагает определенные стандартные методы передачи аргументов в стек.
В частности, слева от компилятора не должно быть пустот, и типы,
меньшие, чем int (например, char и short на машинах с длинным
словом) должны быть объявлены как int.
.зп 2
Сторонний эффект, порядок вычисления
# Язык С дает несколько гарантий порядка оценок операндов в выражении
или аргументов в вызове функции. Таким образом:
# func(i++,i++);
.пс 0
должно рассматриваться как непереносимое, и даже:
# func(i++);
.пс 0
использовать неблагоразумно, если func с какой-то вероятностью
может использоваться в макроопределении, т.к. макроопределение может
использовать i больше одного раза. Определенные макросы XENIX(a)
часто используются в пользовательских программах; они все гарантируют
использование своего аргумента лишь однажды, и поэтому благополучно могут
вызываться с аргументом, исползующим сторонний эффект. Наиболее часто
используемыми примерами являются getc(), putc(), getchar(), putchar.
# Операнды со следующими операторами обязательно вычисляются слева направо:
# , && || ? :
# Отметим, что оператор запятой здесь является разделителем для двух
С-предложений. Список элементов, разделенных запятыми в списке
объявлений, необязательно обрабатывается слева направо. Так, объявление
# register int a, b, c, d;
.пс 0
на PDP-11, где могут быть объявлены только три регистровых переменных,
может присвоить любым трем из четырех переменных регистровый тип,
в зависимости от компилятора. Для правильного объявления, устанавливающего
бесспорный порядок по важности присвоения переменным регистрового типа,
должны использоваться отдельные операторы объявления, т.к. порядок обработки
отдельных операторов объявления обязательно последователен:
.sw
        register int a;
        register int b;
        register int c;
        register int d;

.зп 1
Различия в программном окружении
# Большинство программ для различных нужд используе системные вызовы и
библиотеки подпрограмм. Данный раздел обращает внимание на некоторые
подпрограммы, которые не всегда являются переносимыми, и на подпрограммы,
которые очень помогают переносимости.
# Мы коснемся здесь преимущественно переносимости в операционной системе
XENIX. Большинство системных вызовов XENIX(a) являются специфическими для
частного окружения операционной системы и не существуют для реализаций С
в других операционных системах. Например, getpwent() для доступа к содержимому
файла паролей XENIX(a), или getenv(), который специфичен для концепции
окружения процесса в XENIX(e).
# Любая программа, содержащая полное имя файла или каталога, или использующая
идентификатор пользователя в системе, или зарегистрированное имя пользователя,
параметры терминала и другие системно-зависимые параметры, является не
переносимой. Эти типы констант должны находиться в заголовке файлов,
пердаваться в качестве аргументов командной строки, получаться из окружения,
или получаться при использовании параметров по умолчанию библиотечных
подпрограмм XENIX(a) dfopen и dfread.
# Внутри XENIX(a) большинство системных вызовов и библиотечных подпрограмм
переносимы среди различных машин и реализаций XENIX(a). Однако,
некоторые подпрограммы изменяются  по интерфейсу с пользователем.
Библиотека подпрограмм XENIX(a) обычно переносима среди систем XENIX.
# Отметим, что члены семейства printf (printf, fprintf, sprintf, sscanf и
scanf) изменялись различными путями в течение эволюции XENIX(a),
и некоторые их особенности не всегда переносимы. Возвращаемые величины этих
подпрограмм не обязательно будут иметь одинаковые значения во всех системах.
Некоторые из преобразований форматов символов изменяют их значения,
в особенности те, которые касаются вывода строчных и заглавных символов в
шестнадцатеричном/десятичном виде, и описания длинных (long)
целых на машинах с 16-битным словом. Страница справочного руководства,
посвященная printf, содержит корректное описание этих подпрограмм.
.зп 1
Переносимость данных
# Файлы данных почти всегда не переносимы среди различных машинных
архитектур CPU. Как отмечалось выше, структуры, объединения и массивы имеют
различный внутренний формат и требования к заполнению на различных машинах.
К тому же, порядок байтов внутри слов и действительная длина слова
могут различаться.
# Единственным путем достижения переносимости файлов данных является
запись и чтение файлов данных в виде одномерных символьных массивов.
Это позволит избежать проблем выравнивания и заполнения, если данные
записываются и считываются как символы, и интерпретируются таким способом.
Таким образом, текстовые ASCII файлы могут обычно переноситься на
различные типы машин без слишком больших проблем.
.зп 1
Lint
# Lint - это программа проверки, которая пытается обнаружить особенности
в группе исходных файлов на С, текст которых непереносим или некорректен.
Одним из преимуществ программы lint сверх любой проверки компиляцией
является проверка объявления функций и обращения по всему исходному файлу.
Ни компилятор, ни редактор связей этого не делает.
# Lint выдает предупредительные сообщения о непереносимых арифметических
указателях, присвоениях и преобразованиях типов. Однако, если lint
не выдал никаких предупреждений, это не означает, что программа совершенно
переносима.
.зп 1
Кратко о порядке байтов
# В нижеприведенных таблицах используются следующие соглашения:
# a0 - младший физически адресуемый байт элемента данных. a0+1, и т.д.
# b0 - наименее значимый байт элемента данных; b1 будет следующим наименее
значимым, и т.д.
# Заметим, что все программы, которые действительно будут использовать
это информацию, гарантированно будут непереносимы!
.t2 6 Порядок байтов для коротких типов
        |---------------------------|
        |   CPU   | Порядок байтов  |
        |---------|-----------------|
        |         |  a0    |   b0   |
        |---------------------------|
        |---------|--------|--------|
        | PDP-11  |  b0    |   b1   |
        |---------|--------|--------|
        | VAX-11  |  b0    |   b1   |
        |---------|--------|--------|
        | 8086    |  b0    |   b1   |
        |---------|--------|--------|
        | 286     |  b0    |   b1   |
        |---------|--------|--------|
        | M68000  |  b1    |   b0   |
        |---------|--------|--------|
        | Z8000   |  b1    |   b0   |
        |---------|--------|--------|

.t2 6 Порядок байтов для длинных типов
        |--------------------------------------------|
        |   CPU   |          Порядок байтов          |
        |---------|----------------------------------|
        |         |  a0    |   a1   |   a2   |   a3  |
        |--------------------------------------------|
        |---------|--------|--------|--------|-------|
        | PDP-11  |  b2    |   b3   |   b0   |   b1  |
        |---------|--------|--------|--------|-------|
        | VAX-11  |  b0    |   b1   |   b2   |   b3  |
        |---------|--------|--------|--------|-------|
        | 8086*   |  b0    |   b1   |   b2   |   b3  |
        |---------|--------|--------|--------|-------|
        | 8086**  |  b2    |   b3   |   b0   |   b1  |
        |---------|--------|--------|--------|-------|
        | 286     |  b0    |   b1   |   b2   |   b3  |
        |---------|--------|--------|--------|-------|
        | M68000  |  b3    |   b2   |   b1   |   b0  |
        |---------|--------|--------|--------|-------|
        | Z8000   |  b3    |   b2   |   b1   |   b0  |
        |---------|--------|--------|--------|-------|

# Отметим, что порядок байтов для длинных типов на PDP-11 и машинах на базе
8086 зависит от компилятора (а не от CPU - аппаратуры).
Эта таблица основана для PDP-11 на компиляторе Ritchie.
Строка 8086* показывает  порядок байтов для компиляторов, использующих
порядок слов в XENIX System V (в-конце-младший). Строка 8086**
показывает порядок байтов для компиляторов XENIX 3.0 (в-конце-старший).
Пользователи 8086 могут использовать dtype(C)  для определения,
является ли файловая система пословной.
.пм Include - файлы языка Си
# В таблице приведен список include-файлов для
различных компиляторов языка Си
.тм 5
-------------------------------------------------------------------------------
  Имя             | MSC  | Turbo-C |  XENIX   | OC  | Демос-2 |  OCI   | ANSI
include           | V5.0 |  V1.5   | SYSTEM V | AIX |         | VENIX  |стандарт
 файла            |      |         |          | V1.1|         |        |
------------------|------|---------|----------|-----|---------|--------|-------
a.out.h           |      |         |    +     |  +  |         |        |
alloc.h           |      |   +     |          |     |         |        |
ar.h              |      |         |    +     |  +  |         |        |
assert.h          |  +   |   +     |    +     |  +  |         |        |   +
backup.h          |      |         |          |  +  |         |        |
bios.h            |  +   |   +     |          |     |         |        |
cfg01.h-          |      |         |          |     |         |        |
cfg04.h           |      |         |          |  +  |         |        |
conio.h           |  +   |   +     |    +*    |     |         |        |
core.h            |      |         |    +     |  +  |         |        |
ctype.h           |  +   |   +     |    +     |  +  |         |        |   +
cur01.h-          |      |         |          |     |         |        |
cur05.h           |      |         |          |  +  |         |        |
curses.h          |      |         |    +     |  +  |         |        |
dbm.h             |      |         |    +     |  +  |         |        |
dial.h            |      |         |    +     |     |         |        |
dir.h             |      |   +     |          |     |         |        |
direct.h          |  +   |         |    +*    |     |         |        |
dmpfmt.h          |      |         |          |  +  |         |        |
dos.h             |  +   |   +     |    +*    |  +  |         |        |
doserrno.h        |      |         |          |  +  |         |        |
dumprestor.h      |      |         |    +     |     |         |        |
errno.h           |  +   |   +     |    +     |  +  |         |        |
execargs.h        |      |         |    +     |  +  |         |        |
fatal.h           |      |         |          |  +  |         |        |
fcntl.h           |  +   |   +     |    +     |  +  |         |        |
filechdr.h        |      |         |          |  +  |         |        |
float.h           |  +   |   +     |          |     |         |        |
ftw.h             |      |         |    +     |  +  |         |        |
gpoff.h           |      |         |          |  +  |         |        |
graph.h           |  +   |         |          |     |         |        |
graphics.h        |      |   +     |          |     |         |        |
grp.h             |      |         |    +     |  +  |         |        |
gslerrno.h        |      |         |          |  +  |         |        |
ieeetrap.h        |      |         |          |  +  |         |        |
inu21.h           |      |         |          |  +  |         |        |
io.h              |  +   |   +     |    +*    |     |         |        |
limits.h          |  +   |   +     |          |     |         |        |
linenum.h         |      |         |          |  +  |         |        |
local.h           |      |         |          |     |         |        |   +
lockcmn.h         |      |         |    +     |     |         |        |
lprio.h           |      |         |          |  +  |         |        |
macros.h          |      |         |    +     |  +  |         |        |
malloc.h          |  +   |         |    +     |     |         |        |
math.h            |  +   |   +     |    +     |  +  |         |        |   +
mdverify.h        |      |         |          |  +  |         |        |
mem.h             |      |   +     |          |     |         |        |
memory.h          |  +   |         |    +     |  +  |         |        |
mnttab.h          |      |         |    +     |  +  |         |        |
mon.h             |      |         |    +     |  +  |         |        |
msg00.h-msg10.h   |      |         |          |  +  |         |        |
nan.h             |      |         |          |  +  |         |        |
nlist.h           |      |         |          |  +  |         |        |
process.h         |  +   |   +     |    +*    |     |         |        |
pwd.h             |      |         |    +     |  +  |         |        |
regexp.h          |      |         |    +     |  +  |         |        |
register.h        |      |         |    +*    |     |         |        |
sd.h              |      |         |    +     |     |         |        |
search.h          |  +   |   +     |    +     |  +  |         |        |
setjmp.h          |  +   |   +     |    +     |  +  |         |        |   +
sgtty.h           |      |         |    +     |     |         |        |
share.h           |  +   |   +     |    +*    |     |         |        |
signal.h          |  +   |   +     |    +     |  +  |         |        |   +
stand.h           |      |         |    +     |  +  |         |        |
spawn.h           |      |         |    +*    |     |         |        |
stdarg.h          |  +   |   +     |          |     |         |        |   +
stddef.h          |  +   |   +     |          |     |         |        |   +
stdio.h           |  +   |   +     |    +     |  +  |         |        |   +
stdlib.h          |  +   |   +     |    +*    |     |         |        |   +
string.h          |  +   |   +     |    +     |  +  |         |        |   +
sysm.h            |      |         |          |  +  |         |        |
term.h            |      |         |    +     |  +  |         |        |
termio.h          |      |         |    +     |  +  |         |        |
time.h            |  +   |   +     |    +     |  +  |         |        |   +
uinfo.h           |      |         |          |  +  |         |        |
unctrl.h          |      |         |          |  +  |         |        |
unistd.h          |      |         |    +     |  +  |         |        |
ustat.h           |      |         |    +     |  +  |         |        |
utmp.h            |      |         |    +     |  +  |         |        |
v2tov3.h          |      |         |    +*    |     |         |        |
values.h          |      |   +     |    +     |  +  |         |        |
varargs.h         |  +   |         |    +     |  +  |         |        |
vrcchar.h         |      |         |          |  +  |         |        |
vrcppr.h          |      |         |          |  +  |         |        |
vrm.h             |      |         |          |  +  |         |        |
sys/FP.h          |      |         |          |  +  |         |        |
sys/a.out.h       |      |         |    +     |     |         |        |
sys/acct.h        |      |         |    +     |  +  |         |        |
sys/asdef.h       |      |         |          |  +  |         |        |
sys/assert.h      |      |         |    +     |     |         |        |
sys/bioca.h       |      |         |          |  +  |         |        |
sys/brk.h         |      |         |    +     |     |         |        |
sys/buf.h         |      |         |    +     |  +  |         |        |
sys/callo.h       |      |         |    +     |  +  |         |        |
sys/clock.h       |      |         |          |  +  |         |        |
sys/comcrt.h      |      |         |    +     |     |         |        |
sys/conf.h        |      |         |    +     |  +  |         |        |
sys/console.h     |      |         |    +     |     |         |        |
sys/crtctl.h      |      |         |    +     |     |         |        |
sys/debug.h       |      |         |          |  +  |         |        |
sys/devinfo.h     |      |         |          |  +  |         |        |
sys/dio.h         |      |         |    +     |     |         |        |
sys/dir.h         |      |         |    +     |  +  |         |        |
sys/direache.h    |      |         |          |  +  |         |        |
sys/dump.h        |      |         |          |  +  |         |        |
sys/dynaprobe.h   |      |         |          |  +  |         |        |
sys/elog.h        |      |         |          |  +  |         |        |
sys/erec.h        |      |         |          |  +  |         |        |
sys/err.h         |      |         |          |  +  |         |        |
sys/errno.h       |      |         |    +     |  +  |         |        |
sys/fblk.h        |      |         |    +     |  +  |         |        |
sys/fd.h          |      |         |          |  +  |         |        |
sys/file.h        |      |         |    +     |  +  |         |        |
sys/filsys.h      |      |         |    +     |  +  |         |        |
sys/fpfp.h        |      |         |          |  +  |         |        |
sys/fpfpi.h       |      |         |          |  +  |         |        |
sys/fstypes       |      |         |          |  +  |         |        |
sys/hft.h         |      |         |          |  +  |         |        |
sys/hwdbus.h      |      |         |          |  +  |         |        |
sys/idd.h         |      |         |    +     |     |         |        |
sys/init.h        |      |         |          |  +  |         |        |
sys/ino.h         |      |         |    +     |  +  |         |        |
sys/inode.h       |      |         |    +     |  +  |         |        |
sys/io.h          |      |         |          |  +  |         |        |
sys/iobuf.h       |      |         |    +     |  +  |         |        |
sys/ioctl.h       |      |         |    +     |  +  |         |        |
sys/ipc.h         |      |         |    +     |  +  |         |        |
sys/kcfg.h        |      |         |          |  +  |         |        |
sys/kcs.h         |      |         |          |  +  |         |        |
sys/kio.h         |      |         |          |  +  |         |        |
sys/kmon.h        |      |         |    +     |     |         |        |
sys/kproc.h       |      |         |          |  +  |         |        |
sys/kpsb.h        |      |         |          |  +  |         |        |
sys/ksvc.h        |      |         |          |  +  |         |        |
sys/lock.h        |      |         |    +     |  +  |         |        |
sys/lockcmn.h     |      |         |    +     |     |         |        |
sys/lockf.h       |      |         |          |  +  |         |        |
sys/locking.h     |  +   |         |    +     |     |         |        |
sys/low.h         |      |         |          |  +  |         |        |
sys/lprio.h       |      |         |          |  +  |         |        |
sys/mashdep.h     |      |         |    +     |     |         |        |
sys/map.h         |      |         |    +     |  +  |         |        |
sys/mmu.h         |      |         |    +     |     |         |        |
sys/mount.h       |      |         |    +     |  +  |         |        |
sys/msg.h         |      |         |    +     |  +  |         |        |
sys/ndir.h        |      |         |    +     |     |         |        |
sys/ndp.h         |      |         |    +     |     |         |        |
sys/nfs.h         |      |         |    +     |     |         |        |
sys/opt.h         |      |         |          |  +  |         |        |
sys/param.h       |      |         |    +     |  +  |         |        |
sys/preadi.h      |      |         |    +     |     |         |        |
sys/pri.h         |      |         |          |  +  |         |        |
sys/proc.h        |      |         |    +     |  +  |         |        |
sys/proctl.h      |      |         |    +     |     |         |        |
sys/pty.h         |      |         |          |  +  |         |        |
sys/rebust.h      |      |         |          |  +  |         |        |
sys/reg.h         |      |         |    +     |  +  |         |        |
sys/relsym.h      |      |         |    +     |     |         |        |
sys/relsym86.h    |      |         |    +     |     |         |        |
sys/sd.h          |      |         |    +     |     |         |        |
sys/seg.h         |      |         |          |  +  |         |        |
sys/sem.h         |      |         |    +     |  +  |         |        |
sys/shm.h         |      |         |    +     |  +  |         |        |
sys/signal.h      |      |         |    +     |  +  |         |        |
sys/sites.h       |      |         |    +     |     |         |        |
sys/space.h       |      |         |    +     |  +  |         |        |
sys/stat.h        |  +   |   +     |    +     |  +  |         |        |
sys/sysinfo.h     |      |         |    +     |  +  |         |        |
sys/sysmacros.h   |      |         |    +     |  +  |         |        |
sys/systm.h       |      |         |    +     |  +  |         |        |
sys/tape.h        |      |         |          |  +  |         |        |
sys/termio.h      |      |         |    +     |  +  |         |        |
sys/text.h        |      |         |    +     |  +  |         |        |
sys/timeb.h       |  +   |         |    +     |     |         |        |
sys/times.h       |      |         |    +     |  +  |         |        |
sys/trace.h       |      |         |          |  +  |         |        |
sys/trap.h        |      |         |          |  +  |         |        |
sys/ttold.h       |      |         |    +     |     |         |        |
sys/tty.h         |      |         |    +     |  +  |         |        |
sys/types.h       |  +   |         |    +     |  +  |         |        |
sys/uio.h         |      |         |          |  +  |         |        |
sys/ulimit.h      |      |         |    +     |     |         |        |
sys/user.h        |      |         |    +     |  +  |         |        |
sys/utime.h       |  +   |         |    +*    |     |         |        |
sys/utsname.h     |      |         |    +     |  +  |         |        |
sys/var.h         |      |         |    +     |  +  |         |        |
sys/vrmtimer.h    |      |         |          |  +  |         |        |
.пм Библиотека языка Си
# В таблице приведен список названий функций для
различных компиляторов языка Си
.тм 5
-------------------------------------------------------------------------------
    Имя           | MSC  | Turbo-C |  XENIX   | OC  | Демос-2 |  OC    | ANSI
библиотечной функ-| V5.0 |  V1.5   | SYSTEM V | AIX |         | VENIX  |стандарт
ции или библиотеки|      |         |          | V1.1|         |        |
------------------|------|---------|----------|-----|---------|--------|-------
abort             |  +   |         |          |     |         |        |   +
abs               |  +   |         |          |     |         |        |   +
acces             |  +   |         |          |     |         |        |
acos              |  +   |         |          |     |         |        |   +
asctime           |  +   |         |          |     |         |        |   +
asin              |  +   |         |          |     |         |        |   +
assert            |  +   |         |          |     |         |        |   +
atan              |  +   |         |          |     |         |        |   +
atan2             |  +   |         |          |     |         |        |   +
atexit            |      |         |          |     |         |        |   +
atof              |  +   |         |          |     |         |        |   +
atoi              |  +   |         |          |     |         |        |   +
atol              |  +   |         |          |     |         |        |   +
bessel            |  +   |         |          |     |         |        |
bsearch           |  +   |         |          |     |         |        |   +
cabs              |  +   |         |          |     |         |        |
calloc            |  +   |         |          |     |         |        |   +
ceil              |  +   |         |          |     |         |        |   +
cgets             |  +   |         |          |     |         |        |
chdir             |  +   |         |          |     |         |        |
chmod             |  +   |         |          |     |         |        |
chsize            |  +   |         |          |     |         |        |
_clear87          |  +   |         |          |     |         |        |
clearerr          |  +   |         |          |     |         |        |   +
clock             |      |         |          |     |         |        |   +
close             |  +   |         |          |     |         |        |
compar            |      |         |          |     |         |        |   +
_control87        |  +   |         |          |     |         |        |
cos               |  +   |         |          |     |         |        |   +
cosh              |  +   |         |          |     |         |        |   +
cprintf           |  +   |         |          |     |         |        |
cputs             |  +   |         |          |     |         |        |
creat             |  +   |         |          |     |         |        |
cscanf            |  +   |         |          |     |         |        |
ctime             |  +   |         |          |     |         |        |   +
dieeetomsbin-     |      |         |          |     |         |        |
dmsbintoieee      |  +   |         |          |     |         |        |
difftime          |  +   |         |          |     |         |        |   +
div               |      |         |          |     |         |        |   +
dosexterr         |  +   |         |          |     |         |        |
dup               |  +   |         |          |     |         |        |
dup2              |  +   |         |          |     |         |        |
ecvt              |  +   |         |          |     |         |        |
eof               |  +   |         |          |     |         |        |
execl             |  +   |         |          |     |         |        |
execle            |  +   |         |          |     |         |        |
execlp            |  +   |         |          |     |         |        |
execlpe           |  +   |         |          |     |         |        |
execve            |  +   |         |          |     |         |        |
execvp            |  +   |         |          |     |         |        |
execvpe           |  +   |         |          |     |         |        |
_exit             |  +   |         |          |     |         |        |
exit              |  +   |         |          |     |         |        |   +
exp               |  +   |         |          |     |         |        |   +
expand            |  +   |         |          |     |         |        |
fabs              |  +   |         |          |     |         |        |   +
fclose            |  +   |         |          |     |         |        |   +
fcloseall         |  +   |         |          |     |         |        |
fcvt              |  +   |         |          |     |         |        |
fdopen            |  +   |         |          |     |         |        |
feof              |  +   |         |          |     |         |        |   +
ferror            |  +   |         |          |     |         |        |   +
fflush            |  +   |         |          |     |         |        |   +
_ffree            |  +   |         |          |     |         |        |
fgetc             |  +   |         |          |     |         |        |   +
fgetchar          |  +   |         |          |     |         |        |
fgetpos           |      |         |          |     |         |        |   +
fgets             |  +   |         |          |     |         |        |   +
fieeetomsbin -    |      |         |          |     |         |        |
fmsbintoieee      |  +   |         |          |     |         |        |
filelength        |  +   |         |          |     |         |        |
fileno            |  +   |         |          |     |         |        |
floor             |  +   |         |          |     |         |        |   +
flushall          |  +   |         |          |     |         |        |
_fmalloc          |  +   |         |          |     |         |        |
fmod              |  +   |         |          |     |         |        |   +
_fmsize           |  +   |         |          |     |         |        |
fopen             |  +   |         |          |     |         |        |   +
FP_OFF            |  +   |         |          |     |         |        |
_fpreset          |  +   |         |          |     |         |        |
fprintf           |  +   |         |          |     |         |        |   +
FP_SEG            |  +   |         |          |     |         |        |
fputc             |  +   |         |          |     |         |        |   +
fputchar          |  +   |         |          |     |         |        |
fputs             |  +   |         |          |     |         |        |   +
fread             |  +   |         |          |     |         |        |   +
free              |  +   |         |          |     |         |        |   +
_freect           |  +   |         |          |     |         |        |
frexp             |  +   |         |          |     |         |        |   +
freopen           |  +   |         |          |     |         |        |   +
fscanf            |  +   |         |          |     |         |        |   +
fseek             |  +   |         |          |     |         |        |   +
fsetpos           |      |         |          |     |         |        |   +
fstat             |  +   |         |          |     |         |        |
ftell             |  +   |         |          |     |         |        |   +
ftime             |  +   |         |          |     |         |        |
fwrite            |  +   |         |          |     |         |        |   +
gcvt              |  +   |         |          |     |         |        |
getc              |  +   |         |          |     |         |        |   +
getch             |  +   |         |          |     |         |        |
getche            |  +   |         |          |     |         |        |
getchar           |  +   |         |          |     |         |        |   +
getcwd            |  +   |         |          |     |         |        |
getenv            |  +   |         |          |     |         |        |   +
getpid            |  +   |         |          |     |         |        |
gets              |  +   |         |          |     |         |        |   +
getw              |  +   |         |          |     |         |        |
gmtime            |  +   |         |          |     |         |        |   +
halloc            |  +   |         |          |     |         |        |
hfree             |  +   |         |          |     |         |        |
hypot             |  +   |         |          |     |         |        |
inp               |  +   |         |          |     |         |        |
int86             |  +   |         |          |     |         |        |
int86x            |  +   |         |          |     |         |        |
intdos            |  +   |         |          |     |         |        |
intdosx           |  +   |         |          |     |         |        |
isalnum           |  +   |         |          |     |         |        |   +
isalpha           |  +   |         |          |     |         |        |   +
isatty            |  +   |         |          |     |         |        |
iscntrl           |  +   |         |          |     |         |        |   +
isdigit           |  +   |         |          |     |         |        |   +
isgraph           |  +   |         |          |     |         |        |   +
islower           |  +   |         |          |     |         |        |   +
isprint           |  +   |         |          |     |         |        |   +
ispunct           |  +   |         |          |     |         |        |   +
isspace           |  +   |         |          |     |         |        |   +
isupper           |  +   |         |          |     |         |        |   +
isxdigit          |  +   |         |          |     |         |        |   +
itoa              |  +   |         |          |     |         |        |
kbhit             |  +   |         |          |     |         |        |
labs              |  +   |         |          |     |         |        |   +
ldexp             |  +   |         |          |     |         |        |   +
ldiv              |      |         |          |     |         |        |   +
lfind-lsearch     |  +   |         |          |     |         |        |
localtime         |  +   |         |          |     |         |        |   +
locking           |  +   |         |          |     |         |        |
log               |  +   |         |          |     |         |        |   +
log10             |  +   |         |          |     |         |        |   +
longjmp           |  +   |         |          |     |         |        |   +
lseek             |  +   |         |          |     |         |        |
ltoa              |  +   |         |          |     |         |        |
malloc            |  +   |         |          |     |         |        |   +
matherr           |  +   |         |          |     |         |        |
_memavl           |  +   |         |          |     |         |        |
memchr            |  +   |         |          |     |         |        |   +
memcmp            |  +   |         |          |     |         |        |   +
memcpy            |  +   |         |          |     |         |        |   +
memicmp           |  +   |         |          |     |         |        |
memmove           |      |         |          |     |         |        |   +
memset            |  +   |         |          |     |         |        |   +
mkdir             |  +   |         |          |     |         |        |
mktime            |      |         |          |     |         |        |   +
mktemp            |  +   |         |          |     |         |        |
modf              |  +   |         |          |     |         |        |   +
movedata          |  +   |         |          |     |         |        |
_msize            |  +   |         |          |     |         |        |
_nfree            |  +   |         |          |     |         |        |
_nmalloc          |  +   |         |          |     |         |        |
_nmsize           |  +   |         |          |     |         |        |
offsetof          |      |         |          |     |         |        |   +
onexit            |  +   |         |          |     |         |        |
open              |  +   |         |          |     |         |        |
outp              |  +   |         |          |     |         |        |
perror            |  +   |         |          |     |         |        |   +
pow               |  +   |         |          |     |         |        |   +
printf            |  +   |         |          |     |         |        |   +
putc              |  +   |         |          |     |         |        |   +
putch             |  +   |         |          |     |         |        |
putchar           |  +   |         |          |     |         |        |   +
putenv            |  +   |         |          |     |         |        |
puts              |  +   |         |          |     |         |        |   +
putw              |  +   |         |          |     |         |        |
qsort             |  +   |         |          |     |         |        |   +
raise             |      |         |          |     |         |        |   +
rand              |  +   |         |          |     |         |        |   +
read              |  +   |         |          |     |         |        |
realloc           |  +   |         |          |     |         |        |   +
remove            |  +   |         |          |     |         |        |   +
rename            |  +   |         |          |     |         |        |   +
rewind            |  +   |         |          |     |         |        |   +
rmdir             |  +   |         |          |     |         |        |
rmtmp             |  +   |         |          |     |         |        |
sbrk              |  +   |         |          |     |         |        |
scanf             |  +   |         |          |     |         |        |   +
segread           |  +   |         |          |     |         |        |
setbuf            |  +   |         |          |     |         |        |   +
setlocale         |      |         |          |     |         |        |   +
setjmp            |  +   |         |          |     |         |        |   +
setmode           |  +   |         |          |     |         |        |
setvbuf           |  +   |         |          |     |         |        |   +
signal            |  +   |         |          |     |         |        |   +
sin               |  +   |         |          |     |         |        |   +
sinh              |  +   |         |          |     |         |        |   +
sopen             |  +   |         |          |     |         |        |
sprintf           |  +   |         |          |     |         |        |   +
spawnl-spawnvpe   |  +   |         |          |     |         |        |
sqrt              |  +   |         |          |     |         |        |   +
srand             |  +   |         |          |     |         |        |   +
sscanf            |  +   |         |          |     |         |        |   +
stackvail         |  +   |         |          |     |         |        |
stat              |  +   |         |          |     |         |        |
_status87         |  +   |         |          |     |         |        |
strcat            |  +   |         |          |     |         |        |   +
strchr            |  +   |         |          |     |         |        |   +
strcmp            |  +   |         |          |     |         |        |   +
strcmpi,stricmp   |  +   |         |          |     |         |        |
strcoll           |      |         |          |     |         |        |   +
strcpy            |  +   |         |          |     |         |        |   +
strcspn           |  +   |         |          |     |         |        |
strdup            |  +   |         |          |     |         |        |
strerror          |  +   |         |          |     |         |        |   +
strftime          |      |         |          |     |         |        |   +
strlen            |  +   |         |          |     |         |        |   +
strlwr            |  +   |         |          |     |         |        |
strncat           |  +   |         |          |     |         |        |   +
strncmp           |  +   |         |          |     |         |        |   +
strncpy           |  +   |         |          |     |         |        |   +
strnicmp          |  +   |         |          |     |         |        |
strnset           |  +   |         |          |     |         |        |
strpbrk           |  +   |         |          |     |         |        |   +
strrchr           |  +   |         |          |     |         |        |
strrev            |  +   |         |          |     |         |        |
strset            |  +   |         |          |     |         |        |
strspn            |  +   |         |          |     |         |        |   +
strstr            |  +   |         |          |     |         |        |   +
strtod            |  +   |         |          |     |         |        |   +
strtok            |  +   |         |          |     |         |        |   +
strtol            |  +   |         |          |     |         |        |   +
strtoul           |      |         |          |     |         |        |   +
strupr            |  +   |         |          |     |         |        |
swab              |  +   |         |          |     |         |        |
system            |  +   |         |          |     |         |        |   +
tan               |  +   |         |          |     |         |        |   +
tanh              |  +   |         |          |     |         |        |   +
tell              |  +   |         |          |     |         |        |
tempnam           |  +   |         |          |     |         |        |
time              |  +   |         |          |     |         |        |   +
tmpfile           |  +   |         |          |     |         |        |   +
tmpnam            |  +   |         |          |     |         |        |   +
toascii           |  +   |         |          |     |         |        |
tolower           |  +   |         |          |     |         |        |   +
toupper           |  +   |         |          |     |         |        |   +
tzset             |  +   |         |          |     |         |        |
ultoa             |  +   |         |          |     |         |        |
umask             |  +   |         |          |     |         |        |
ungetc            |  +   |         |          |     |         |        |   +
unlink            |  +   |         |          |     |         |        |
utime             |  +   |         |          |     |         |        |
va_start          |  +   |         |          |     |         |        |   +
va_arg            |  +   |         |          |     |         |        |   +
va_end            |  +   |         |          |     |         |        |   +
vfprintf          |  +   |         |          |     |         |        |   +
vprintf           |  +   |         |          |     |         |        |   +
vsprintf          |  +   |         |          |     |         |        |   +
write             |  +   |         |          |     |         |        |