Книга: Linux программирование в примерах

1.3. Стандартный С против оригинального С

1.3. Стандартный С против оригинального С

В течение многих лет определение С де-факто можно было найти в первом издании книги Брайана Кернигана и Денниса Ричи «Язык программирования С» (Brian Kernighan & Dennis Ritchie, The С Programming Language). Эта книга описала С, как он существовал для Unix и на системах, на которые его перенесли разработчики лаборатории Bell Labs. На протяжении данной книги мы называем его как «оригинальный С», хотя обычным является также название «С Кернигана и Ричи» («K&R С»), по именам двух авторов книги. (Деннис Ричи разработал и реализовал С.)

Стандарт ISO С 1990 г.[17] формализовал определения языка, включая функции библиотеки С (такие, как printf() и fopen()). Комитет по стандартам С проделал замечательную работу по стандартизации существующей практики и избежал введения новых возможностей, с одним значительным исключением (и несколькими незначительными). Наиболее заметным изменением языка было использование прототипов функций, заимствованных от С++.

Стандартные языки программирования С, C++ и Java используют прототипы функций для объявлений и определений функций. Прототип описывает не только возвращаемое значение функции, но также и число и тип ее аргументов. С прототипами компилятор может выполнить проверку типов в точке вызова функции:

Объявление

extern int myfunc(struct my_struct *a,
 struct my_struct *b, double c, int d);

Определение

int myfunc(struct my_struct *a,
 struct my_struct *b, double c, int d) {
 ...
}
...
struct my_struct s, t;
int j;
...
/* Вызов функции, где-то в другом месте: */
j = my_func(&s, &t, 3.1415, 42);

Это правильный вызов функции. Но рассмотрите ошибочный вызов:

j = my_func(-1, -2, 0);
/* Ошибочные число и типы аргументов */

Компилятор может сразу же определить этот вызов как неверный. Однако, в оригинальном С функции объявляются без указания списка аргументов:

extern int myfunc();
/* Возвращает int, аргументы неизвестны */

Более того, определения функций перечисляют имена параметров в заголовке функции, затем объявляют параметры перед телом функции. Параметры типа int объявлять не нужно, и если функция возвращает int, его тоже не нужно объявлять:

myfunc(a, b, с, d); /* Возвращаемый тип int*/
struct my_struct *а, *b;
double с;
/* Обратите внимание, нет объявления параметра d*/
{
 ...
}

Рассмотрите снова тот же ошибочный вызов функции: 'j = my_func(-1, -2 , 0);'. В оригинальном С у компилятора нет возможности узнать, что вы (ошибочно, полагаем) передали my_func() ошибочные аргументы. Подобные ошибочные вызовы обычно приводят к трудно устранимым проблемам времени исполнения (таким, как ошибки сегментации, из-за чего программа завершается), и для работы с такими вещами была создана программа Unix lint.

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

Для С стандарта 1990 г. код, написанный в оригинальном стиле, является действительным как для объявлений, так и для определений. Это дает возможность продолжать компилировать миллионы строк существующего кода с помощью компилятора, удовлетворяющего стандарту. Новый код, очевидно, должен быть написан с прототипами из-за улучшенных возможностей проверки ошибок времени компилирования.

Стандарт С 1999 г.[18] продолжает допускать объявления и определения в оригинальном стиле. Однако, правило «неявного int» было убрано; функции должны иметь возвращаемый тип, а все параметры должны быть объявлены.

Более того, когда программа вызывала функцию, которая не была формально объявлена, оригинальный С создал бы для функции неявное объявление с возвращаемым типом int. С стандарта 1999 г. делал то же самое, дополнительно отметив, что у него не было информации о параметрах. С стандарта 1999 г. не предоставляет больше возможности «автоматического объявления».

Другими заметными дополнениями в стандарте С являются ключевое слово const, также из С++, и ключевое слово volatile, которое придумал комитет. Для кода, который вы увидите в этой книге, наиболее важной вещью является понимание различных синтаксисов объявлений и определений функций.

Для кода V7, использующего определения в оригинальном стиле, мы добавили комментарии, показывающие эквивалентный прототип. В остальных случаях мы оставили код как есть, предпочитая показать его точно таким, каким он был первоначально написан, и как бы вы его увидели, если бы сами загрузили код.

Хотя стандарт С 1999 г. добавляет некоторые дополнительные ключевые слова и возможности, отсутствующие в версии 1990 г., мы решили придерживаться диалекта 1990 г, поскольку компиляторы C99 не являются пока типичными. Практически, это не имеет значения: код C89 должен компилироваться и запускаться без изменений при использовании компилятора C99, а новые возможности C99 не затрагивают наше обсуждение или использование фундаментальных API Linux/Unix.

Оглавление книги


Генерация: 0.281. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз