Linux программирование в примерах | страница 21



формализовал определения языка, включая функции библиотеки С (такие, как >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 г. код, написанный в оригинальном стиле, является действительным как для объявлений, так и для определений. Это дает возможность продолжать компилировать миллионы строк существующего кода с помощью компилятора, удовлетворяющего стандарту. Новый код, очевидно, должен быть написан с прототипами из-за улучшенных возможностей проверки ошибок времени компилирования.