В этой главе будет приведено несколько примеров использования таких средств.
Я ввел в язык С++ комментарии
//
, унаследованные от его предшественника, языка BCPL, когда мне надоело печатать комментарии вида
/* ... */
. Комментарии
//
приняты в большинстве диалектов языка, включая версию C99,
поэтому их можно использовать совершенно безопасно. В наших примерах мы будем использовать комментарии вида
/* ... */
исключительно для того, чтобы показать, что мы пишем программу на языке C. В языке C99 реализованы некоторые возможности языка C++ (а также некоторые возможности, несовместимые с языком С++), но мы будем придерживаться версии C89, поскольку она используется более широко.
27.1.3. Стандартная библиотека языка С
Естественно, возможности библиотек языка С++, зависящие от классов и шаблонов, в языке С недоступны. Перечислим некоторые из них.
• Класс
vector
.
• Класс
map
.
• Класс
set
.
• Класс
string
.
• Алгоритмы библиотеки STL: например,
sort
,
find
и
copy
.
• Потоки ввода-вывода
iostream
.
• Класс
regex
.
Из-за этого библиотеки языка С часто основаны на массивах, указателях и функциях. К основной части стандартной библиотеки языка С относятся следующие заголовочные файлы.
•
<stdlib.h>
. Общие утилиты (например,
malloc
и
free
; см. раздел 27.4).
•
<stdio.h>
. Стандартный механизм ввода-вывода; см. раздел 27.6.
•
<string.h>
. Манипуляции со строками и памятью в стиле языка C; см. раздел 27.5.
•
<math.h>
. Стандартные математические функции для операций над числами с плавающей точкой; см. раздел 24.8.
•
<errno.h>
. Коды ошибок математических функций из заголовочного файла
<math.h>
; см. раздел 24.8.
•
<limits.h>
. Размеры целочисленных типов; см. раздел 24.2.
•
<time.h>
. Функции даты и времени; см. раздел 26.6.1.
•
<assert.h>
. Условия для отладки (debug assertions); см. раздел 27.9.
•
<ctype.h>
. Классификация символов; см. раздел 11.6.
•
<stdbool.h>
. Булевы макросы.
Полное описание стандартной библиотеки языка С можно найти в соответствующем учебнике, например в книге K&R. Все эти библиотеки (и заголовочные файлы) также доступны и в языке С++.
27.2. Функции
В языке C есть несколько особенностей при работе с функциями.
• Может существовать только одна функция с заданным именем.
• Проверка типов аргументов функции является необязательной.
• Ссылок нет (а значит, нет и механизма передачи аргументов по ссылке).
• Нет функций-членов.
• Нет подставляемых функций (за исключением версии C99).
• Существует альтернативный синтаксис объявления функций.
Помимо этого, все остальное мало отличается от языка С++. Изучим указанные отличия по отдельности.
Второе объявление является ошибкой, потому что в программе, написанной на языке С, не может быть двух функций с одним и тем же именем. Итак, нам необходимо придумать подходящую пару имен.
void print_int(int); /* печать целого числа int */
Иногда это свойство называют преимуществом: теперь вы не сможете случайно использовать неправильную функцию для вывода целого числа! Очевидно, что нас такой аргумент убедить не сможет, а отсутствие перегруженных функций усложняет реализацию идей обобщенного программирования, поскольку они основаны на семантически похожих функциях, имеющих одинаковые имена.
27.2.2. Проверка типов аргументов функций
Рассмотрим следующий пример:
int main
{
f(2);
}
Компилятор языка С допускает такой код: вы не обязаны объявлять функции до их использования (хотя можете и должны). Определение функции
f
может находиться где-то в другом месте. Кроме того, функция
f
может находиться в другом модуле компиляции, в противном случае редактор связей сообщит об ошибке.
К сожалению, это определение в другом исходном файле может выглядеть следующим образом:
/* other_file.c: */
int f(char* p)
{
int r = 0;
while (*p++) r++;
return r;
}
Редактор связей не сообщит об этой ошибке. Вместо этого вы получите ошибку на этапе выполнения программы или случайный результат.
Как решить эту проблему? На практике программисты придерживаются согласованного использования заголовочных файлов. Если все функции, которые вы вызываете или определяете, объявлены в заголовке, поставленном в соответствующее место программы с помощью директивы
#include
, будет включен механизм проверки типов. Однако в больших программах на это трудно рассчитывать. Вследствие этого в большинстве компиляторов языка С существуют опции, предусматривающие выдачу предупреждений о вызовах необъявленных функций: воспользуйтесь ими. Кроме того, с первых дней существования языка C появились программы, с помощью которых можно выявлять все возможные проблемы, связанные непротиворечивостью типов. Обычно они называются lint. Используйте их для любой нетривиальной программы на языке С. Вы обнаружите, что программы lint подталкивают вас использовать язык С как подмножество языка С++. Одно из наблюдений, приведших к разработке языка С++, состояло в том, что компилятор мог легко проверять многое (но не все), что могли проверять программы