Как декларация функции ANSI C является улучшением в стиле старого Кернигана и Ричи?

With regards to the ANSI C function declaration, how is this an improvement from the old K&R style? I know the differences between them, I just want to know what problems could arise from using the old style and how the new style is an improvement.

5
nl ja de
Я вижу, что есть голос, чтобы закрыть это. Я согласен, что вопрос потенциально расплывчатый, но я считаю, что есть конкретный ответ (см. Мой).
добавлено автор Keith Thompson, источник

2 ответы

Объявление в стиле старого стиля , в частности, не позволяет проводить проверку вызовов во время компиляции.

Например:

int func(x, y)
char *x;
double y;
{
     /* ... */
}

...

func(10, 20);

Когда компилятор видит вызов, он не знает типы параметров функции func , поэтому он не может диагностировать ошибку.

В отличие от этого:

int better_func(char *x, double y) {
    /* ... */
}

...

better_func(10, 20);

приведет к сообщению об ошибке компилятора (или, по крайней мере, предупреждению).

Другое усовершенствование: прототипы позволяют иметь функции с параметрами типа float , а целочисленных типов более узкие, чем int (типы char и два short ). Без прототипа float продвигается до double , а узкие целые типы повышаются до int или unsigned int , С прототипом аргумент float передается как float (если функция не является переменной, например printf ), и в этом случае применяются старые правила к вариационным аргументам).

Документ C Обоснование обсуждает это в разделе 6.7 .5.3, вероятно, лучше, чем у меня:

Механизм прототипа функции является одним из наиболее полезных дополнений   на язык C. Эта функция, конечно, имеет прецедент во многих   на языках Алгола за последние 25 лет. Конкретная форма   принятая в стандарте, во многом основана на C ++.

     

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

     

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

Есть больше; пошли читать.

8
добавлено
@templatetypedef: Не обязательно. Функция non-prototype в стиле старого стиля Объявление не включает тело функции, поэтому она не предоставляет информацию о типе параметров. Пример: int func (); в some_header.h . Полное определение предоставляет эту информацию, но (а) оно, вероятно, не должно находиться в одном исходном файле, и (б) компилятор не должен использовать его, даже если он есть. Вызов непрототируемой функции с недопустимыми аргументами имеет неопределенное поведение; его не нужно диагностировать.
добавлено автор Keith Thompson, источник
@RichardGray: Вопросы формы «Почему X лучше Y» часто могут «запрашивать дискуссии, аргументы, опросы или расширенную дискуссию». Я думаю, что ваш вопрос является исключением из этого.
добавлено автор Keith Thompson, источник
@RichardGray: Я добавил дополнительную информацию в свой ответ.
добавлено автор Keith Thompson, источник
Почему компилятор не обнаруживает несоответствие типа с функцией стиля K & R? Вся информация о типе все еще присутствует.
добавлено автор templatetypedef, источник
Интересно отметить, что стиль K & R намного более соответствует основной идее объявлений C; «использование имитаций объявления».
добавлено автор bames53, источник
Большое вам спасибо, я не уверен, как они могли считать мой вопрос таким же расплывчатым, потому что вы ответили ему за меня отлично, спасибо еще раз :)
добавлено автор Richard Gray, источник

A non-defining function declaration in K&R looks as follows

int foo();

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

A function declaration, which is used as a part of function definition in K&R looks as follows

int foo(a, b) 
int a;
char b;
{ ...

Он определяет количество параметров, но не указывает их типы. Более того, даже несмотря на то, что количество параметров, по-видимому, отображается этим объявлением, оно по-прежнему формально объявляет foo так же, как int foo (); делает, что означает, что вызов поскольку foo (1, 2, 3, 4, 5) по-прежнему не является нарушением ограничения.

Новый стиль, то есть декларация с прототипом, лучше по понятным причинам: он предоставляет как количество, так и типы параметров. Это заставляет компилятор проверить правильность вызова (в отношении количества и типов параметров). И это позволяет компилятору выполнять неявные преобразования типов из типов аргументов в типы параметров.

There are other, less obvious benefits provided by prototype declarations. Since the number and types of function parameters are known precisely to both the caller and the function itself, it is possible to choose the most efficient method of passing the arguments (the calling convention) at the point of the call without seeing the function definition. Without that information K&R implementations were forced to follow a single pre-determined "one size fits all" calling convention for all functions.

3
добавлено