С помощью следующего кода:Вопросы о C Прототипы функций и Сборнике
int main(){
printf("%f\n",multiply(2));
return 0;
}
float multiply(float n){
return n * 2;
}
Когда я пытаюсь скомпилировать я получаю одно предупреждение: «„% е“ожидает„двойной“, но аргумент имеет тип„Int“» и две ошибки: «конфликтующие типы для« multiply »,« предыдущее неявное объявление «multiply» было здесь ».
Вопрос 1: Я предполагаю, что это потому, что, учитывая компилятор не имеет знания о функции «умножение», когда он приходит через него в первый раз, он будет изобрести прототип, и изобрел прототипы всегда предполагать «Int» оба возвращаются и принимаются как параметр. Таким образом, изобретенный прототип будет «int multiply (int)», и, следовательно, ошибки. Это верно?
Теперь предыдущий код даже не компилируется. Однако, если я нарушу код в двух файлах, как это:
#file1.c
int main(){
printf("%f\n",multiply(2));
return 0;
}
#file2.c
float multiply(float n){
return n * 2;
}
и выполнить «НКУ file1.c file2.c -o файл» он все равно будет давать одно предупреждение (что Printf ожидает двойной, но получает Int), но ошибки больше не появятся, и они будут компилироваться.
Вопрос 2: Как происходит, когда я разбиваю код на 2 файла, который он компилирует?
Вопрос 3: После запуска программы выше (версия разбита на 2 файла) результатом является то, что на экране печатается 0,0000. Как так? Я предполагаю, что компилятор снова изобрел прототип, который не соответствует функции, но почему печатается 0? И если я изменил printf («% f») на printf («% d»), он напечатает 1. Опять же, какое-либо объяснение того, что происходит за кулисами?
Большое спасибо.
Имеет смысл. Единственный момент, который до сих пор не ясен, - это то, почему компилятор не найдет ложь/противоречие с 2 файлами. В конце концов, он все равно создаст прототип int multiply (int) при работе через main.c, и как только он попадет во второй файл, он встретит объявление функции float multiply (float), что явно противоречит предыдущему опытный образец. –
@ Даниэль Хороший момент! Я отредактировал ответ, чтобы упомянуть, почему: по сути, компилятор компилирует каждый файл отдельно, по одному источнику за раз. Это отличается от, скажем, Java, который рассматривает все файлы одновременно. С C и C++ каждая единица перевода (это причудливое имя для файла .c') компилируется отдельно, а затем компоновщик собирает результаты вместе. К тому моменту, когда линкер попадает в игру, вся информация о типе отсутствует: компоновщики работают на гораздо более низком уровне байтов, смещений и адресов, поэтому они также не могут обнаружить расхождение. – dasblinkenlight
@ DanielS: компилятор работает с одним файлом за раз; работая над файлом 'file1.c', он ничего не знает о содержимом' file2.c' и наоборот. При создании 'file1.c' он знает только, что' multiply' не был объявлен перед использованием. При создании 'file2.c' он не знает, что' multiply' используется в другой единицы перевода без соответствующего объявления в области видимости. –