будут собраны все описания из исходных файлов и библиотек,
промежуточный файл сортируется для объединения вместе всей
собранной информации о каждой конкретной внешней переменной.
Вторая, довольно маленькая, программа читает затем строки из
промежуточного файла и сравнивает все определения, объявле-
ния и использования на совместимость.

Программа-драйвер управляет указанным процессом, а
также несет ответственность за то, чтобы заданные ключи были
известны обоим проходам программы lint.

15. Переносимость

В различных реализациях языка Си допускались отступле-
ния от стандарта языка системы UNIX. Тем не менее многие
Си-программы были с небольшими усилиями успешно перенесены


- 13 -










на различные установки. В данном разделе описываются неко-
торые различия реализаций Си, а также обсуждаются полезные
свойства программы lint.

Неинициализированные внешние переменные обрабатываются
по-разному в различных реализациях языка Си. Предположим,
что имеются два файла, каждый из которых содержит вне
какой-либо функции объявление без инициализации (например,
int a;). Редактор свзей ДЕМОС при обработке этих объявлений
выделит для a только одно слово памяти. В рамках некоторых
реализаций это невозможно (по различным причинам, которые
трудно счесть разумными!), и каждое такое объявление влечет
заведение своего внешнего имени. В момент загрузки это при-
ведет к фатальному конфликту. Если программа lint будет
вызвана с флагом -c, то такие многократные объявления будут
выявлены.

Аналогичные трудности возникают при представлении внеш-
них имен в объектном файле. В системе ДЕМОС внешние имена
имеют семь значащих символов, причем учитывается различие
верхнего и нижнего регистров. В системах ЕС ЭВМ число зна-
чащих символов равно восьми, однако различие регистров игно-
рируется. Данное обстоятельство может порождать ситуации,
когда программа, работающая в ДЕМОС не собирается в других
системах. Использование флага -p вызывает преобразование
всех имен внешних переменных к одному регистру и усекает их
до шести символов, предусматривая при этом анализ "худшего
случая".

Некоторые трудности возникают и при обработке символов:
символы в ДЕМОС представляются восемью битами в коде КОИ-8,
в ОС ЕС используется восьмибитных код ДКОИ. Кроме того,
строки символов располагаются от старшей к младшей битовой
позиции ("слева направо") в системах ЕС, и от младшей к
старшей позиции ("справа налево") на СМ-1420. Это означает,
что фрагмент программы, выполняющий построение строк не из
символьных констант, или использующий символы в качестве
индексов массивов, должен проверяться очень внимательно.
lint не может существенно помочь в данной ситуации, за иск-
лючением указания символьных констант, состоящих из несколь-
ких символов.

Естественно, размеры слова в разных машинах могут раз-
личаться. Однако, это вызывает меньше затруднений, чем
можно было бы ожидать, по крайней мере, при переносе с 16-
битной машины на 32-битную. По всей вероятности, основные
проблемы возникают при сдвигах и маскировании. В настоящее
время язык Си обеспечивает обработку битовых полей, что поз-
воляет писать значительную часть таких кодов с высокой сте-
пенью переносимости. Часто переносимость таких программ
может быть расширена путем небольшой перестройки стиля прог-
раммирования. Многие из несовместимостей являются, по-
видимому, следствием записей типа


- 14 -










x &= 0177700

для обнуления шести младших битов x. Будучи удовлетвори-
тельной для СМ-1420, такая запись приведет к тяжелой ошибке
на ЕС ЭВМ. Желаемый эффект может быть получен при использо-
вании контсрукции:

x &= 077;

которая выполняется правильно на всех рассматриваемых маши-
нах.

Операция сдвига вправо является арифметическим сдвигом
на СМ-1420 и логическим сдвигом на большинстве других машин.
Для получения логического сдвига для всех машин, левый опе-
ранд может задаваться в виде целого без знака. Символы счи-
таются целыми со знаком в СМ-1420, но целыми без знака в
других машинах. Такое "поведение" знакового бита может быть
справедливо расценено как ошибка аппаратурой PDP-11, харак-
теристики которой оказали определенное влияние на язык Си.
Если бы имелся приемлемый способ обнаружения программ, в
которых встречается указанная трудность, язык Си мог бы быть
изменен. Во всяком случае, программа lint здесь бессильна.

Приведенные выше примеры могут создать впечатление, что
проблема переносимости представляет больше трудностей, чем
это есть в действительности. Возникающие здесь вопросы
редко бывают неуловимыми или загадочными, по крайней мере
для разработчика программы, хотя и могут иногда потребовать
определенной работы по их устранению. Значительно более
серьезным препятствием для переносимости утилит системы
ДЕМОС является невозможность имитировать существенные функ-
ции системы ДЕМОС на других системах. Невозможность доступа
к символу, находящемуся в произвольной позиции в текстовом
файле, или невозможность установления межпрограммного интер-
фейса требует значительно большей переработки и отладки, чем
любые различия в компиляторах языка Си. С другой стороны,
программа lint является очень полезной при переносе операци-
онной системы ДЕМОС и связанных с ней программ-утилит на
другие машины.

16. Управление выдачей сообщений

Бывают случаи, когда программист умнее программы lint.
Так, могут быть веские причины для использования "недопусти-
мых" изменений типа, функций с переменным числом аргументов
и т.д. Более того, как указано выше, информация о потоке
управления, порождаемая lint, часто имеет "слепые пятна",
что может вызвать случайные ложные сообщения о вполне разум-
ных программах. Таким образом, желательно иметь некоторые
способы связи с lint, обычно для подавления таких ложных
сообщений.



- 15 -










Форма, которую должен иметь такой механизм, не вполне
ясна. Дело в том, что введение, например, новых ключевых
слов потребовало бы от современных и старых компиляторов
обеспечения распознавания этих слов или по крайней мере их
игнорирования. При этом возникают как философские, так и
практические трудности, в частности потребует изменения син-
таксис нового препроцессора.

В конце было решено, что ряд слов, находящихся внутри
комментариев, должен распознаваться программой lint. Это
потребовало минимальных изменений в препроцессоре: препро-
цессор пропускает комментарии в свой выход, а не удаляет их,
как это делалось раньше. Таким образом, директивы lint
являются невидимыми для компиляторов; эффект этих изменений
для систем со старыми препроцессорами заключается только в
том, что эти директивы программы lint на этих системах не
работают.

Первая директива относится к информации о потоке управ-
ления: если какой-то участок программы не может быть достиг-
нут, а программе lint это не очевидно, то его можно указать
программе lint с помощью директивы /* NOTREACHED */, поме-
щенной в подходящей точке программы. Подобным образом, если
желательно отключить строгую проверку типов в последующим
выражении, то может быть использована директива

/* NOSTRICT */

После обработки этого выражения lint возвратится в прежнее
(принимаемое по умолчанию) состояние. Флаг -v может быть
включен для одной функции с помощью директивы

/* ARGUSED */

Сообщения о различном числе аргументов при обращениях к
некоторой функции могут быть подавлены директивой

/* VARARGS */

помещенной перед определением данной функции. В некоторых
случаях желательно проверять несколько первых аргументов,
оставляя остальные аргументы непроверенными. Это может быть
указано ключевым словом VARARGS, за которым следует цифра,
задающая число аргументов, которые должны быть проверены;
так,

/* VARARGS2 */

вызывает проверку лишь первых двух аргументов. Наконец,
директива

/* LINTLIBRARY */



- 16 -










помещенная в заголовке файла, указывает, что данный файл
является файлом объявления библиотеки. Этой теме посвящен
следующий раздел.

17. Файлы объявления библиотек

Программа lint допускает несколько библиотечных дирек-
тив, подобных -ly, и проверяет исходные файлы на совмести-
мость с этими библиотеками. Это осуществляется путем дос-
тупа в файлы описания библиотек, имена которых (файлов)
строятся из библиотечных директив. Все такие файлы начина-
ются директивой

/* LINTLIBRARY */

за которой следует серия пустых определений функций. Крити-
ческими частями этих определений являются: определение типа
возвращаемого функцией значения, вопрос - не возвращает ли
пустая функция некоторого значения, а также число и типы
аргументов функции. Для указания особенностей данных библи-
отечных функций могут быть использованы директивы VARARGS и
ARGUSED.

Библиотечные файлы lint обрабатываются почти в точности
так же, что и обычные исходные файлы. Единственное различие
заключается в том, что о функциях, определенных в библиотеч-
ном файле, но не использованных в исходном файле, не выда-
ется никаких сообщений. Программа lint не моделирует полный
алгоритм поиска в библиотеке, и выдает предостерегающее
сообщение в случае, если исходные файлы содержат переопреде-
ление некоторой библиотечной функции (это-особенность!).

По умолчанию программа lint сверяет указанные ей прог-
раммы со стандартным библиотечным файлом, содержащим описа-
ние программ, которые обычно загружаются при работе программ
на языке Си. При задании флага -p проверяется другой файл,
содержащий описание стандартных программ библиотеки
ввода/вывода, которые, как ожидается, обладают переноси-
мостью на различные машины. Для подавления всех проверок
библиотек можно использовать флаг -n.

18. Ошибки и т.д.

При создании программы lint разработчики встретились со
значительными трудностями, отчасти обусловленными тесной
связью с вопросами стиля программирования, а отчасти тем,
что пользователи обычно не уведомляют о ситуациях, в которых
программа пропускает ошибки, о которых она должна бы была
информировать. (Интересно, что в случаях, когда lint оши-
бочно сообщает о несуществующих на самом деле ошибках, прог-
раммисты откликаются немедленно).




- 17 -










Дальнейшее усовершенствование программы lint можно
вести в нескольких направлениях. Так, недостаточно адек-
ватна проверка структур и массивов, никаких попыток проверки
соответствия объявлений структур и объединений в различных
файлах. Ясно, что желательно несколько более строгая про-
верка использования определения типов typedef; однако вопрос
о том, какой уровень контроля будет достаточен и как доби-
ваться этого - еще требует определения.

Программа lint делит препроцессор с Си-компилятором.
Это может оказаться благоприятным обстоятельством для созда-
ния специальной версии препроцессора, охватывающего ряд не
выполняемых в настоящее время проверок, таких как неисполь-
зуемые макроопределения, макроаргументы которых имеют побоч-
ные эффекты, или которые не расширяются вообще, или расширя-
ются более чем один раз и т.д.

Центральной проблемой, связанной с lint, является упа-
ковка собираемой информации. Имеется много ключей, служащих
единственно для выключения или небольшого изменения тех или
иных особенностей обработки. Имеется тенденция включения
еще большего числа таких ключей.

В заключение отметим, что складывается впечатление, что
основная идея создания двух программ оказалась удачной.
Компилятор концентрируется на быстром и точном переводе
программного текста в исполняемый код, а программа lint
занимается главным образом вопросами переносимости, стиля и
эффективности. Программа lint может позволить себе оши-
баться, поскольку некорректность и излишний консерватизм,
хотя и раздражают, но не губительны. Компилятор может рабо-
тать быстро, поскольку он "знает", что программа lint в
сложной ситуации "прикроет его фланги". Наконец, програм-
мист может сосредоточиться исключительно на таких аспектах
процесса программирования, как описание алгоритмов и струк-
тур данных и корректности программы, а затем обеспечить с
помощью lint желаемые свойства универсальности т переноси-
мости.

ПРИЛОЖЕНИЕ. Список имеющихся ключей команды lint

В настоящее время команда lint имеет следующий формат:

lint [-ключи] файлы ... дескрипторы-библиотеки...


Ключами являются:

h Осуществлять эвристический контроль

p Осуществлять контроль переносимости




- 18 -










v Не выдавать сообщений о неиспользуемых аргументах

u Не выдавать сообщений о неиспользуемых или неопределен-
ных внешних переменных

b Выдавать сообщения о недостижимых операторах break

x Выдавать сообщения о неиспользованных объявлениях внеш-
них переменных

a Выдавать сообщения о присваиваниях значений типа long
значениям типа int или коротким

c Выдавать сообщения о сомнительных изменениях типов

n Не производить контроля библиотек

s То же, что и h (по историческим причинам).

ЛИТЕРАТУРА

1. B.W.Kernighan and D.M.Ritchie, The C Programming
Language, Prentice-Hall, Englewood Cliffs, New Jersey
(1978).

2. S.C.Johnson, "Yacc - Yet Another Compile-Compiler.",
Comp.Sci.Tech.Rep., No. 32, Bell Laboratiries, Murray
Hill, New Jersey (July 1975).

3. M.E.Lesk, "Lex - a Lexical Analyzer Generator",
Comp.Sci.Tech.Rер., No 39, Bell Laboratories, Murray
Hill, New Jersey (October 1975)

4. S.C.Johnson and D.M.Ritchie, "UNIX Time-Sharing System:
Portability of C Programs and the Unix System,
"Bell.Sys.Tech.J.57(6) pp.2071-2043(1975).

5. S.C.Johnson, "A Portable Compiler: Theory and Prac-
tice", Proc. 5th ACM Symp. on Principles of Programming
Languages, (January 1978).















- 19 -










СОДЕРЖАНИЕ



АННОТАЦИЯ ......................................... 2

ВВЕДЕНИЕ .......................................... 3

1. Вызов программы ................................... 3

2. Некоторые замечания ............................... 4

3. Неиспользованные переменные и функции ............. 4

4. Информация об инициализации и использовании пере-
менных ............................................ 5

5. Поток управления .................................. 6

6. Значения функций .................................. 7

7. Изменения типов ................................... 8

8. Использование символов, нарушающее переносимость. . 9

9. Присваивание целым типа int значений типа long .... 9

10. Странные конструкции .............................. 10

11. О ранних версиях языка ............................ 11

12. Выравнивание указателей ........................... 12

13. Многократные использования и побочные эффекты ..... 12

14. Реализацияч ....................................... 13

15. Переносимость ..................................... 13

16. Управление выдачей сообщений ...................... 15

17. Файлы объявления библиотек ........................ 17

18. Ошибки и т.д. ..................................... 17

ПРИЛОЖЕНИЕ. Список имеющихся ключей команды lint .. 18

ЛИТЕРАТУРА ........................................ 19







- 20 -