Несоответствие прототипа функции c просто предупреждение - PullRequest
3 голосов
/ 24 сентября 2011

пожалуйста, посмотрите мои коды ниже

#include <stdio.h>

void printOut()
{
 static int i = 0;
 if (i < 10)
 {
  printOut(i);
 }
}

int main(int argc, char *argv[])
{

  return 0;
}

Я предполагаю, что должна быть ошибка из-за моего вызова прототипа несуществующей функции. На самом деле, код хорошо компилируется с компилятором mingw5, что странно для меня, затем я перехожу на Borland Compiler, я получаю предупреждающее сообщение: что нет прототипа функции printOut, это только предупреждение? Более того, код хорошо работает без всплывающих окон с ошибками.

Ответы [ 2 ]

6 голосов
/ 24 сентября 2011

В C функция без каких-либо параметров может принимать параметры.

Именно поэтому она компилируется.Способ указать, что он не принимает никаких параметров:

void printOut(void)

Это правильный способ, но он менее распространен, особенно для тех, кто имеет опыт работы с C ++.

5 голосов
/ 24 сентября 2011

Поведение вашей программы не определено, потому что вы определяете printOut() без параметров, но вызываете его с одним аргументом.Вы должны это исправить.Но вы написали это так, что компилятору не требуется диагностировать проблему.(gcc, например, не предупреждает о несоответствии параметров, даже с -std=c99 -pedantic -Wall -Wextra -O3.)

Причины этого исторические.

До ANSI C (до1989) не было прототипов;Объявления функций не могут указывать ожидаемый тип или количество аргументов.Функция definition , с другой стороны, задала параметры функции, но не так, чтобы компилятор мог использовать ее для диагностики несовпадающих вызовов.Например, функция с одним параметром int может быть объявлена ​​(скажем, в файле заголовка) следующим образом:

int plus_one();

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

int plus_one(n)
int n;
{
     return n + 1;
}

Информация о параметрах была скрыта внутри определения.

ANSI C добавил прототипы, поэтому приведенное выше можно записать так:

int plus_one(int n);

int plus_one(int n)
{
    return n + 1;
}

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

В вашем определении:

void printOut()
{
    ...
}

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

Если вы хотите, чтобы ваша функция printOut () не имела параметров и , вам нужен компиляторчтобы жаловаться, если вы называете это неправильно, определите это как:

void printOut(void)
{
    ...
}

Это единственный и единственный правильный способ написать это в C.

Конечно, если вы просто внесете это изменение ввашей программы, а затем добавьте вызов к printOut() в main(), у вас будет бесконечный рекурсивный цикл в ваших руках.Вы, вероятно, хотите, чтобы printOUt() принял аргумент int:

void printOut(int n)
{
    ...
}

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

...