Вы написали свою программу так, чтобы она характеризовала c из очень старых C программ, относящихся к 1980-м или 1990-м годам, до того, как объявления прототипных функций стали предпочтительным стилем. C компиляторы по сей день изгибаются назад, чтобы поддерживать работу этих очень старых программ, сохраняя языковые функции, на которые они полагаются, но которые никогда не были стандартизированы или были удалены из стандарта C с 1989 года.
Совершенно правильный современный стиль для вашей первой программы выглядел бы так:
#include <stdio.h>
double cubenum(double);
int main(void)
{
printf("Answer is: %f", cubenum(3.0));
return 0;
}
double cubenum(double number)
{
double result = number * number * number;
return result;
}
с прототипом предварительное объявление cubenum
, double cubenum(double);
Это Важно понимать, что double cubenum();
НЕ является объявлением-прототипом в C, а скорее объявлением, которое говорит, что cubenum
принимает любое число и тип аргументов. Если вы хотите указать, что cubenum
принимает без аргументов, вам нужно будет написать double cubenum(void);
По этой же причине я изменил int main()
на int main(void)
.
Когда вы выходите предварительное объявление полностью,
#include <stdio.h>
int main(void)
{
printf("Answer is: %f", cubenum(3.0));
return 0;
}
double cubenum(double number)
{
double result = number * number * number;
return result;
}
C компилятор видит вызов cubenum
без какого-либо предыдущего объявления вообще. Это было распространено в тех очень старых C программах, о которых я говорил. Они полагались на функцию под названием неявное объявление , которая была частью исходного стандарта C, но удалена из его редакции 1999 года (обычно известной как «C99»). По сути, компилятор предполагает, что программист намеревался написать int cubenum();
выше main
, но лениво не учел это. Это означает, что cubenum
принимает любое число и тип аргументов (НЕ то, что он не принимает аргументов) и возвращает int
. Итак, оставив пока main
, это похоже на то, что вы написали
int cubenum();
double cubenum(double number) { ... }
, и компилятор отклоняет программу, потому что определение cubenum
имеет тип возврата, отличный от (неявного) прямого объявления , Эта часть, я думаю, вы уже поняли.
Теперь, когда вы изменяете cubenum
, чтобы ничего не возвращать, значит ваша полная программа
#include <stdio.h>
int main(void)
{
printf("Answer is: %f", cubenum(3.0));
return 0;
}
void cubenum(double number)
{
double result = number * number * number;
printf("Answer is: %f", result);
}
, неявное объявление функции по-прежнему int cubenum()
и прототип из определения функции void cubenum(double)
. В качестве еще одной функции совместимости для этих очень старых C программ они считаются , а не конфликтующими типами возврата, и компилятор принимает программу. Это связано с тем, что тип void
был изобретен в стандарте 1989 C. Программы, написанные до этого, вместо этого давали бы cubenum
вообще никакого типа возврата ...
cubenum(number)
double number;
{
double result = number * number * number;
printf("Answer is: %f", result);
}
... что технически объявляет, что он возвращает int
! Сразу после C89 эти программы были обновлены, чтобы дать своим функциям без возвращаемого значения тип void
, но было слишком много работы, чтобы перестать полагаться на неявные объявления для них одновременно, поэтому компиляторы выросли в особый случай, когда int foo()
и void foo()
считаются не конфликтующими.
(Между прочим, из-за еще одного соображения обратной совместимости - «определения функций старого стиля», которые вы можете видеть в приведенном выше фрагменте кода - предпочтительнее) стиль в C состоит в том, чтобы поместить открывающую фигурную скобку определения функции на отдельной строке, даже если все остальные открывающие скобки «обнимаются».)
И, наконец, когда вы делаете поставить void cubenum();
выше main
, только тогда компилятор официально узнает, что cubenum
ничего не возвращает. Когда он это знает, он знает, что printf("%f", cubenum(3.0));
неверно, потому что он использует несуществующее возвращаемое значение cubenum
, и отклоняет программу по причине .
Вы не должны полагаться ни на одну из этих функций обратной совместимости в новой программе. Я вижу, что вы используете G CC, поэтому настройте параметры компиляции примерно так:
-std=gnu11 -g -Og -Wall -Wpedantic -Wstrict-prototypes -Wold-style-definition -Werror
, что отключит почти все функции обратной совместимости. (Существует намного больше опций предупреждения , и вы можете рассмотреть возможность их включения. -Wwrite-strings
и -Wextra
особенно полезны для нового кода IMNSHO. ) (НЕ ИСПОЛЬЗУЙТЕ гиперконформный режим, -std=c11
, пока вы не узнаете значительно больше о том, что вы делаете, он может сломать системные заголовки и разрешить ошибочное «триграфное» ошибочное впечатление, которое вам почти наверняка не нужно. )