Когда моя программа состоит из двух файлов:
main.c
#include <stdio.h>
int main(void) {
printf("%lf\n",f());
return 0;
}
func.c
double f(int a) {
return 1;
}
компилятор не показывает ошибок.
Когда моя программа состоит только из одного файла:
main.c
#include <stdio.h>
int main(void) {
printf("%lf\n",f());
return 0;
}
double f(int a) {
return 1;
}
Компилятор Visual C++ 2008 года показывает следующую ошибку:
Error 2 error C2371: 'f' : redefinition; different basic types d:\temp\projects\function1\function1\1.c 8 function1
Кто-либо может объяснить это странное поведение?
Обе программы неверны.
Без прототипа в области видимости компилятор предполагает, что функция возвращает int
и принимает неопределенное количество параметров.
Давайте немного изменим ваши файлы:
$ cat func.c
double f(int a) {
return 1.0;
}
$ cat main.c
#include <stdio.h>
int main(void) {
double d = f();
printf("%lf\n", d);
return 0;
}
Когда я компилирую его, gcc предупреждает меня (Visual C ++ тоже должен, в совместимом режиме). Но давайте проигнорируем предупреждение.
$ gcc -std=c99 -pedantic -W -Wall func.c main.c -o test
func.c:1: warning: unused parameter 'a'
main.c: In function 'main':
main.c:4: warning: implicit declaration of function 'f'
$ ./test
0.000000
Он не напечатал 1, а напечатал 0. Это потому, что компилятор предположил, что f ()
вернул int
, а присваивание d = f () ;
преобразовал это " int
" в double
. Компилятор по-прежнему скомпилировал код, потому что он не мог сказать, что f ()
не был определен так, как он был (неявно) объявлен. Но компиляция вышеуказанной программы не требуется стандартом, поэтому компилятор мог ее отклонить (например, попробуйте с помощью gcc -Werror
!)
Если у нас все в одном файле:
$ cat func.c >>main.c
$ gcc -std=c99 -pedantic -W -Wall func.c main.c -o test
main.c:4: warning: implicit declaration of function 'f'
main.c: At top level:
main.c:9: error: conflicting types for 'f'
main.c:4: error: previous implicit declaration of 'f' was here
main.c:9: warning: unused parameter 'a'
Теперь компилятор видит конфликт и выдает сообщение об ошибке. Но компилятор не обязан отклонять указанную выше программу, он может или не может.
Большинство компиляторов не отвергают первую программу, потому что они не знают, есть ли у вас правильное определение функции f ()
в другой единице трансляции. Они отвергают вторую программу, потому что они знают , что вы не знаете.
В вашем первом примере никогда не используется func.c
, поэтому я не совсем уверен, что компилятор делает с f ( )
, потому что у него нет определения.
Во втором примере я не знаю, почему у вас не может быть двух функций с разными сигнатурами, но вы не вызываете функцию, которую вы определили. Вы вызываете f ()
без аргументов, но определяемый вами f
принимает int, что делает его другой функцией.
C предполагает, что функция имеет прототип int func (); если вы не указали иное. (Обратите внимание, что в C int func (); и int func (void); - разные вещи)
Во втором случае вы вызываете f ()
для которого компилятор не видел прототипа, поэтому он предполагает, что это int f ();
. Позже он видит ваше определение для f ()
, имеющего другой прототип, и выдает ошибку.
Этого не происходит в 1. случае, поскольку они находятся в разных единицах компиляции.