Поведение компилятора C со старыми функциями без прототипов - PullRequest
5 голосов
/ 18 февраля 2010

Когда моя программа состоит из двух файлов:

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

Кто-нибудь может объяснить это странное поведение?

Ответы [ 3 ]

6 голосов
/ 18 февраля 2010

C предполагает, что функция имеет прототип int func (); если вы не сказали это иначе (обратите внимание, что в C int func (); и int func (void); это разные вещи)

Во втором случае вы вызываете f(), для которого компилятор не видел прототипа, поэтому он предполагает, что это int f();. Позже он видит ваше определение для f(), который имеет другой прототип - и выдает ошибку.

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

5 голосов
/ 18 февраля 2010

Обе программы неверны.

Без прототипа в области видимости компилятор предполагает, что функция возвращает 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() в другой единице перевода или нет. Они отвергают вторую программу, потому что они знают , что вы не знаете.

0 голосов
/ 18 февраля 2010

Ваш первый пример никогда не использует func.c, поэтому я не уверен, что именно делает компилятор с f(), потому что у него нет определения.

Во втором примере я не знаю, почему у вас не может быть двух функций с разными сигнатурами, но вы не вызываете функцию, которую вы определили. Вы вызываете f() без аргументов, но определяемый вами f принимает int, что делает его другой функцией.

...