
\chapter*{Предисловие к русскому изданию}
\addcontentsline{toc}{chapter}{Предисловие к русскому изданию}

Читателю предлагается второе, существенно переработанное издание книги, впервые
опубликованной в США в 1978 г. Книга написана авторами языка Си, и прошедшие
годы дают все основания отнести её к программистской классике. Перевод первого
издания вышел в издательстве <<Финансы и статистика>> в 1985 г. и стал той
книгой, которую многие программисты хотели бы иметь как настольную.

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


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

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

Перечислим основные термины, по которым имеются расхождения.

\smallskip
{\setlength{\LTleft}{\codeIndent-\tabcolsep}%
\SetLenVarWithVal{\Thirdlen}{(\linewidth-\LTleft-5\tabcolsep-\codeIndent)/3}%
\noindent\hspace{\LTleft}\begin{tabular}
{p{\Thirdlen}p{\Thirdlen}l}
\multirow{2}{*}{В оригинале}&В переводе&В переводе\\
&первого издания&второго издания\\
\hline
character&символ&литера\\
structure&запись&структура\\
member&элемент&член\\
union&смесь&объединение\\
pipe&канал&трубопровод\\
line&строчка, строка&строка\\
string&строка&стринг\\
statement&оператор&инструкция\\
operator&операция&оператор\\
operation&операция&операция\\
declaration&описание&декларация\\
tag&тип записи&тег
\end{tabular}}
\smallskip

Новации, как легко заметить, в частности, состоят в следующем. Введён термин
\emph{стринг}, чтобы можно было разными английскими терминами \emph{line} и
\emph{string} поставить в соответствие разные русские термины. Термин
\emph{statement} везде переводится как \emph{инструкция} с тем, чтобы
освободить \emph{оператор} для употребления в традиционном смысле -- как знак
операции.

Из того что не вошло в таблицу отметим термины \emph{инкрементация} и
\emph{декрементация}, полученные <<калькированием>> английских incrementation
и decrementation соответственно. Мы отважились внести эти термины, поскольку
убеждены, что всё, что широко употребляется в жизни, рано или поздно будет
признано в качестве термина, хотя в течение какого-то времени и квалифицируется
как жаргон. Нам кажется, что чем скорее перестанут считаться жаргоном <<теги>>,
<<скипы>>, <<пайпы>>, <<хеширования>>, <<стринги>> и т. п., тем лучше.
Вспомните, какой горячий протест в своё время вызывали дисплей или файл, и
подумайте, как настрадается тот, кто пытается обойтись без этих слов сегодня.
Тенденции мировой интеграции и конвергенции очевидны и неодолимы, и мы не
скрываем своего желания сближать русские и английские термины.

Наконец, последнее замечание. В оригинале употребляется термин
\emph{white space character}, собирательный для литер пробела, табуляции, новой
строки, новой страницы и т. п. Нам не хватило смелости (может быть, напрасно)
ввести <<белый интервал>> или что-нибудь подобное, и мы остановились на
\emph{пробельной литере}.

В заключение хочется выразить благодарность А. Б. Ходулёву, за неоценимую
помощь, оказанную им в овладении техническими и программными средствами, которые
были использованы при подготовке на компьютере оригинал-макета книги.

\hfill \textit{Вс. С. Штаркман}

\chapter*{Предисловие}
\addcontentsline{toc}{chapter}{Предисловие}

С момента публикации в 1978 г. книги <<Язык программирования Си>> в мире
компьютеров произошла революция. Большие машины стали ещё больше, а возможности
персональных ЭВМ теперь сопоставимы с возможностями больших машин десятилетней
давности. Язык Си за это время также изменился, хотя и не очень сильно; что же
касается сферы применения Си, то она далеко вышла за рамки его начального
назначения как инструментального языка операционной системы UNIX. 

Рост популярности Си, накапливающиеся с годами изменения, создание компиляторов
коллективами разработчиков, ранее не причастных к проектированию языка, -- всё
это послужило стимулом к более точному и отвечающему времени определению языка
по сравнению с первым изданием книги. В 1983 г.
\index{American National Standards Institute (ANSI)}%
Американским институтом национальных стандартов (American National Standards
Institute -- ANSI) учреждается комитет, перед которым ставится цель выработать
<<однозначное и машинно-независимое определение языка Си>>, полностью сохранив
при этом его стилистику. Результатом работы этого комитета и явился стандарт
ANSI языка Си.

Стандарт формализует средства языка, которые в первом издании были только
намечены, но не описаны, как, например, присваивание структурам и перечислимый
тип; вводит новый вид описания функций, который позволяет проводить повсеместную
проверку согласованности вызовов функции с её определением; специфицирует
стандартную библиотеку с широким набором функций ввода-вывода, управления
памятью, манипуляций со стрингами (цепочками литер) и другими функциями;
уточняет семантику, которая в первоначальном определении была неясной, и явно
очерчивает то, что остаётся машинно-зависимым.

Второе издание книги <<Язык программирования Си>> описывает версию Си, принятую
в качестве стандарта ANSI. Мы решили описать язык заново, отметив при этом те
места, в которых он претерпел изменения. В большинство разделов это не привнесло
существенных изменений, самые заметные различия касаются новой формы описания и
определения функции. Следует отметить, что современные компиляторы уже
обеспечили поддержку значительной части свойств стандарта.

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

Приложение~\ref{apx:ref_manual} -- справочное руководство, но отнюдь не
документ стандарта. В нём мы попытались <<предметы первой необходимости языка>>
уложить на минимуме страниц. По замыслу это приложение должно легко читаться
программистом-пользователем; для разработчиков компилятора в качестве
определения языка предназначен сам стандарт. В приложении~\ref{apx:stdlib}
собраны функции стандартной библиотеки. Оно также представляет собой справочник
для программистов, но не для реализаторов. Приложение~\ref{apx:sum_of_changes}
содержит краткий перечень отличий от начальной версии языка.

В предисловии к первому изданию мы говорили о том, что <<чем больше работаешь с
Си, тем он становится удобнее>>. Это впечатление только усилилось после десяти
лет работы с ним. Мы надеемся, что данная книга поможет вам изучить Си и успешно
его использовать.

Мы в большом долгу перед друзьями, которые помогали нам в выпуске второго
издания. Джон Бентли, Дуг Гуин, Дуг Макилрой, Питер Нельсон и Роб Пайк дали нам
чёткие замечания почти по каждой странице первого варианта рукописи. Мы
благодарны Алу Ахо, Деннису Аллиссону, Джою Кемпбеллу, Г. Р. Эмлину, Карен
Фортганг, Аллену Голубу, Эндрю Хьюму, Дэйву Кристолу, Джону Линдерману, Дэйву
Проссеру, Гину Спаффорду и Крис Ван Уику за внимательное прочтение книги. Мы
получили полезные советы от Била Чезвика, Марка Кернигана, Эндрю Коэнига, Робина
Лейка, Тома Лондона, Джима Ридза, Кловиза Тондо и Питера Вайнбергера. Дэйв
Проссер ответил на многочисленные вопросы, касающиеся деталей стандарта ANSI.
Мы широко пользовались транслятором с Си++ Бьёрна Строустрапа для локальной
проверки наших программ, а Дэйв Кристол предоставил нам ANSI-Си-компилятор для
окончательной их проверки. Рич Дрешлер очень помог в наборе книги.
%
% исправлена опечатка
% имена Дэйва Проссера и Дэйва Кристола при втором упоминании
% были написаны как "Дейв"
%

Мы искренне благодарим всех.

\hfill \textit{Бриан В. Керниган}

\hfill \textit{Деннис М. Ритчи}

\chapter*{Предисловие к первому изданию}
\addcontentsline{toc}{chapter}{Предисловие к первому изданию}

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

Первоначально Си был спроектирован
\index{Ритчи Д. М.--А.}%
Деннисом Ритчи как инструмент написания операционной системы UNIX для машины
PDP-11 и реализован в рамках этой операционной системы. И операционная система,
и Си-компилятор, и, по существу, все прикладные программы системы UNIX (включая
и те, которые использовались для подготовки текста этой книги\footnote{Имеется в
виду оригинал этой книги на английском языке. -- \textit{Примеч. пер.}})
написаны на Си. Фирменные Си-компиляторы существуют и на нескольких машинах
других типов, среди которых IBM/370, Honeywell 6000 и Interdata 8/32. Си не
привязан к конкретной аппаратуре или системе, однако на нём легко писать
программы, которые без каких-либо изменений переносятся на другие машины, где
осуществляется его поддержка.

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

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

Наш опыт показал, что Си -- удобный, выразительный и гибкий язык, пригодный для
широкого класса задач. Его легко выучить, и чем больше работаешь с Си, тем он
становится удобнее. Мы надеемся, что эта книга поможет вам хорошо его освоить. 

Вдумчивая критика и предложения многих друзей и коллег были очень полезны для
книги и помогали нам её писать. В частности Майк Бианки, Джим Блу, Стью Фелдман,
Дуг Макилрой, Бил Рум, Боб Розин и Ларри Рослер с вниманием прочли все
многочисленные варианты этой книги. Мы в долгу у Ала Ахо, Стива Бьерна, Дана
Дворака, Чука Хейли, Марион Харрис, Рика Холта, Стива Джонсона, Джона Машея,
Боба Митца, Ральфа Мухи, Питера Нельсона, Эллиота Пинсона, Била Плейджера,
Джерри Спивака, Кена Томпсона и Питера Вайнбергера за полезные советы,
полученные от них на различных стадиях подготовки рукописи, а также Майку Леску
и Джо Оссанне за помощь при подготовке её издания.

\hfill \textit{Бриан В. Керниган}

\hfill \textit{Деннис М. Ритчи}

\chapter*{Введение}
\addcontentsline{toc}{chapter}{Введение}

Си -- универсальный язык программирования. Он тесно связан с системой UNIX, так
как был разработан в этой системе, которая как и большинство программ,
работающих в ней, написаны на Си. Однако язык не привязан жёстко к какой-то
одной операционной системе или машине. Хотя он и назван <<языком системного
программирования>>, поскольку удобен для написания компиляторов и операционных
систем, оказалось, что на нём столь же хорошо писать большие программы другого
профиля.

Многие важные идеи Си взяты из языка BCPL, автором которого является
\index{Ричардс М.}%
Мартин Ричардс. Влияние BCPL на Си было косвенным -- через язык B, разработанный
\index{Томпсон К. Л.}%
Кеном Томпсоном в 1970 г. для первой системы UNIX, реализованной на PDP-7.

BCPL и B -- <<безтиповые>> языки. В отличие от них Си обеспечивает разнообразие
типов данных. Базовыми типами являются литеры, а также целые и плавающие числа
различных размеров. Кроме того, имеется возможность получать целую иерархию
\index{выводимые типы}%
\index{типы!выводимые}%
выводимых типов данных из указателей, массивов, структур и объединений.
Выражения формируются из операторов и операндов. Любое выражение, включая
присваивание и вызов функции, может быть инструкцией. Указатели обеспечивают
машинно-независимую адресную арифметику.

В Си имеются основные управляющие конструкции, используемые в
хорошо структурированных программах: составная инструкция (\{\ldots\}),
ветвление по условию (if-else), выбор одной альтернативы из многих
(switch), циклы с проверкой наверху (while, for) и с проверкой внизу
(do), а также средство прерывания цикла (break).

В качестве результата функции могут возвращать значения базовых типов, структур,
объединений и указателей. Любая функция допускает рекурсивное обращение к себе.
Как правило, локальные переменные функции -- <<автоматические>>, т.е они
создаются заново при каждом обращении к ней. Определения функций нельзя
вкладывать друг в друга, но декларации переменных разрешается строить в
блочно-структурной манере. Функции программы на Си могут храниться в отдельных
исходных файлах и компилироваться независимо. Переменные по отношению к функции
могут быть внутренними и внешними. Последние могут быть доступными в пределах
одного исходного файла или всей программы.

На этапе препроцессирования выполняется макроподстановка в текст программы,
включение других исходных файлов и условная компиляция.

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

В Си нет прямых операций над составными объектами, такими, как стринги,
множества, списки и массивы. В нём нет операций, которые бы манипулировали с
целыми массивами или стрингами, хотя структуры разрешается копировать целиком
как единые объекты. В языке нет каких-либо средств распределения памяти, помимо
возможности определения статических переменных и стекового механизма при
выделении места для локальных переменных функций. Нет в нём
<<\verb|heap|-памяти>> (<<памяти-кучи>>, куда обычно <<сваливают>> разнородную
информацию) и <<сборщика мусора>>. Наконец, в самом Си нет средств ввода-вывода,
инструкций READ (читать) и WRITE (писать) и каких-либо методов доступа к файлам.
Все это -- механизмы высокого уровня, которые в Си должны быть обеспечены
исключительно с помощью явно вызываемых функций. Большинство реализованных
Си-систем содержат в себе разумный стандартный набор этих функций.

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

Отсутствие некоторых из перечисленных средств может показаться серьёзным
недостатком (<<выходит, чтобы сравнить две цепочки литер, нужно обращаться к
функции?>>). Однако компактность языка имеет реальные выгоды. Поскольку Си
относительно мал, то и описание его кратко, и овладеть им можно быстро.
Программист может реально рассчитывать на то, что он будет знать, понимать и на
практике регулярно пользоваться всеми возможностями языка.

В течение многих лет единственным определением языка Си было первое издание
книги <<Язык программирования Си>>. В 1983 г. Институтом американских
национальных стандартов (ANSI) учреждается комитет для выработки современного
исчерпывающего определения языка Си. Результатом его работы явился стандарт для
Си (<<ANSI-C>>), выпущенный в 1988 г. Большинство положений стандарта уже учтено
в современных компиляторах.

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

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

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

Второй значительный вклад стандарта -- это определение библиотеки, поставляемой
вместе с Си-компилятором, в которой специфицируются функции доступа к
возможностям операционной системы (например, чтения-записи файлов), форматного
ввода-вывода, динамического запроса памяти, манипуляций со стрингами (цепочками
литер) и т. д. Набор стандартных головных файлов обеспечивает единообразный
доступ к описаниям функций и типов данных. Гарантируется, что программы,
использующие эту библиотеку при взаимодействии с операционной системой, будут
работать также и на других машинах. Большинство программ, составляющих
библиотеку, созданы по образу и подобию <<стандартной библиотеки ввода-вывода>>
системы UNIX. Эта библиотека описана в первом издании книги и широко
используется в других системах. И здесь программисты не заметят существенных
различий.

\index{переносимость}%
Так как типы данных и управляющих структур языка Си поддерживаются командами
большинства существующих машин, административная система обеспечения
независимого запуска и счёта программ очень мала. Обращения к библиотечным
функциям пишет сам программист (не компилятор), поэтому при желании их можно
легко заменить на другие. Почти все программы, написанные на Си, если они не
касаются каких-либо деталей, скрытых в операционной системе, переносимы на
другие машины.

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

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

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

Тем не менее, как оказалось, Си -- чрезвычайно эффективный и выразительный
язык, пригодный для широкого класса задач. Книга имеет следующую структуру.
Гл.~\ref{chapt:tutorial_intro} -- это обзор основных средств языка Си. Её
назначение побудить читателя по возможности быстрее приступить к
программированию, так как мы убеждены, что единственный способ изучить новый
язык -- это писать на нём программы. Эта часть книги предполагает наличие знаний
по основным элементам программирования. Никаких пояснений того, что такое
компьютер, компиляция или что означает выражение вида $n=n+1$ не даётся. Хотя мы
и пытались, там, где это возможно, показать полезные приёмы программирования,
эта книга не призвана быть справочником ни по работе со структурами данных, ни
по алгоритмам; когда оказывалось необходимым выбрать, на что сделать ударение,
мы предпочитали сконцентрировать внимание на языке.

В гл.~\ref{chapt:types-operators-expressions}--\ref{chapt:structures} различные
средства языка обсуждаются более подробно и несколько более формально, чем в
гл.~\ref{chapt:tutorial_intro}; при этом по-прежнему упор делается на примеры,
являющиеся законченными программами, а не изолированными фрагментами.
Гл.~\ref{chapt:types-operators-expressions} знакомит с базовыми типами данных, с
операторами и выражениями. В гл.~\ref{chapt:control_flow} рассматриваются
средства управления последовательностью вычислений: if-else, switch, while, for
и т. д. В гл.~\ref{chapt:functions_and_program_structure} речь идёт о функциях и
структуре программы (внешних переменных, правилах видимости, делении программы
на несколько исходных файлов и т.д.), а также о препроцессоре. В
гл.~\ref{chapt:pointers_and_arrays} обсуждаются указатели и адресная арифметика.
Гл.~\ref{chapt:structures} посвящена структурам и объединениям.

В гл.~\ref{chapt:input-output} описана стандартная библиотека, обеспечивающая
общий интерфейс с операционной системой. Эта библиотека узаконена в качестве
стандарта ANSI, иначе говоря, она должна быть представлена на всех машинах, где
существует Си, благодаря чему программы, использующие ввод-вывод и другие
возможности операционной системы, без каких-либо изменений можно переносить с
одной машины на другую.

Гл.~\ref{chapt:unix_system_interface} содержит описание интерфейса между
программами на Си и операционной системой UNIX, в частности описание
ввода-вывода, файловой системы и распределения памяти. Хотя некоторые разделы
этой главы отражают специфику системы UNIX, программисты, пользующиеся другими
системами, всё же найдут в них много полезных сведений, включая определённый
взгляд на то, как реализуется одна из версий стандартной библиотеки, и некоторые
предложения по переносимости программ.

Приложение~\ref{apx:ref_manual} является справочником по языку. Строгое
определение синтаксиса и семантики языка Си содержится в официальном документе
стандарта ANSI. Последний, однако, более всего подходит разработчикам
компилятора. Наш справочник определяет язык более сжато, не прибегая к
законодательному стилю, которым пользуется стандарт. Приложение~\ref{apx:stdlib}
-- сводка по содержимому стандартной библиотеки и предназначена скорее
пользователям, чем реализаторам. В приложении~\ref{apx:sum_of_changes}
приводится краткий перечень отличий от первой версии языка. В неясных случаях,
однако, окончательным судьёй по языку остаётся стандарт и компилятор, которым вы
пользуетесь.
