Путать вызов функции в синтаксисе до ANSI C - PullRequest
5 голосов
/ 29 сентября 2011

Я имею дело с некоторым синтаксисом до ANSI C.Смотрите, у меня есть следующий вызов функции в одном условном

 BPNN *net;
 // Some more code
 double val;
 // Some more code, and then,
 if (evaluate_performance(net, &val, 0)) {

Но тогда функция evaluate_performance была определена следующим образом ( ниже функция, которая имеет вышеупомянутое условное выражение):

evaluate_performance(net, err)
BPNN *net;
double *err;
{

Почему evaluate_performance был определен с двумя параметрами, но вызван с тремя аргументами?Что означает «0»?

И, кстати, я совершенно уверен, что он не вызывает какой-то другой evaluate_performance, определенный в другом месте;Я grep просмотрел все файлы, и я почти уверен, что мы должны говорить об одном и том же evaluate_performance.

Спасибо!

Ответы [ 4 ]

7 голосов
/ 29 сентября 2011

Если вы вызываете функцию, у которой нет объявленного прототипа (как в данном случае), то компилятор предполагает, что он принимает произвольное число и типы аргументов, и возвращает int. Кроме того, char и short аргументы повышаются до int с, а float s повышаются до double с (они называются продвижениями аргументов по умолчанию ).

Это считается плохой практикой в ​​новом C-коде по понятным причинам - если функция не возвращает int, плохая ситуация может гарантировать, что вы не позволите компилятору проверить, что вы передаете правильное число и типы параметры и аргументы могут выдвигаться неправильно.

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

Что касается дополнительных параметров, они технически неопределенное поведение в соответствии со стандартом C89. Но на практике они обычно просто игнорируются средой выполнения.

3 голосов
/ 29 сентября 2011

Код неверен, но компилятор не требует диагностики.(Компилятор C99 будет жаловаться на это.)

Определения функций старого стиля не указывают количество аргументов, ожидаемых функцией.Предполагается, что вызов функции без видимого прототипа возвращает int и имеет число и тип (ы) аргументов, подразумеваемых вызовами (с узкими целочисленными типами, которые повышаются до int или unsigned int, и float повышен до double).(C99 удалил это; ваш код недопустим в соответствии со стандартом C99.)

Это применимо, даже если определение предшествует вызову (определение старого стиля не предоставляет прототип).

Если такая функция вызывается неправильно, поведение не определено.Другими словами, ответственность за правильность аргументов лежит исключительно на программисте;компилятор не будет диагностировать ошибки.

Это, очевидно, не идеальная ситуация;это может привести к множеству необнаруженных ошибок.

Именно поэтому ANSI добавила в язык прототипы.

Почему вы все еще работаете с определениями функций старого стиля?Можете ли вы обновить код для использования прототипов?

2 голосов
/ 29 сентября 2011

Даже стандартные компиляторы C несколько допустимы, когда дело доходит до этого. Попробуйте выполнить следующее:

int foo()
{
   printf("here");
}

int main()
{
   foo(3,4);
   return 0;
}

К некоторому удивлению он выдаст "here". Дополнительные аргументы просто игнорируются. Конечно, это зависит от компилятора.

1 голос
/ 29 сентября 2011

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

Это должен быть довольно старый компилятор, чтобы не ошибиться в этом, или он еще не нашел объявление функции!

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

Обратите внимание, что это можно сделать (добавить дополнительные параметры) при использовании многоточия, как в printf ():

printf(const char *format, ...);

Я бы предположил, что в какой-то момент функция имела 3 параметра, а последний был удален, потому что он не использовался, а некоторые части кода не были исправлены, как должно быть. Я бы удалил этот 3-й параметр, на случай, если стек пойдет в неправильном порядке и, следовательно, не сможет отправить правильные параметры в функцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...