2012-01-11 2 views
3

Я работаю через K & R, чтобы научиться программированию. Хорошо продвигаться до сих пор, но я не понимаю о роли строки кода из раздела 1.8 (функции).Какова цель этой строки? (Объявление функции)

В разделе 1.8 авторы показывают, как создать функцию, которая может поднять одно целое число до другого целого.

Я наклеил код ниже, как написано в книге. Все выводится нормально. Но я не знаю, почему они включили эту линию в верхней части:

int power(int m, int n); 

Книга не упоминает об этом, кроме сказать, что программа поднимет число т к мощности п. Если я удалю строку из кода, программа по-прежнему будет выводиться так, как должна.

Если я понимаю правильно, линия

int power(int base, int n) 

создает функцию, а фигурные скобки под определение функции. Затем скобки под основным вызовом выполняют функцию вывода диаграммы.

Так что все это имеет смысл. Но я не понимаю, что делает сама верхняя линия.

Это может быть посторонним, но, похоже, гораздо более вероятно, что я что-то упустил. Может ли кто-нибудь просветить меня, почему эта линия есть?

#include <stdio.h> 

int power(int m, int n); 

/* test power function */ 
main() 
{ 
int i; 

    for (i = 0; i < 10; ++i) 
     printf("%d %d %d\n", i, power(2,i), power(-3, i)); 
    return 0; 
} 

/* power: raise base to n-th power; n >= 0 */ 

int power(int base, int n) 
{ 
    int i, p; 

    p = 1; 
    for (i = 1; i <= n; ++i) 
     p = p * base; 
    return p; 
} 

ответ

6

Первая строка - это функции.Блок кода внизу - это определение функции.

Начиная с версии стандарта ISO C 1999 года, это незаконно (нарушение ограничения) для вызова функции без видимого объявления; объявление должно предшествовать вызову.

Для простой программы, подобной этой, вы можете просто написать полное определение power() перед определением main() (поскольку определение также содержит декларацию), но для более сложных случаев (например, рекурсивных вызовов) вам часто требуется для предоставления отдельной декларации.

Для более крупных программ, это общая для сбора всех функций объявления в файле заголовок (foo.h, например), и соответствующие определения в исходном файле (foo.c, например). A #include "foo.h" директива используется, чтобы сделать объявления видимыми в других файлах. Вы увидите это позже в книге.

(В 1990-х и более ранних версиях C, что есть K & R2 охватывает, есть случаи, когда вы можете вызывать функцию без видимого объявления, но в любом случае все равно очень полезно предоставлять явные объявления.)

Кстати, декларация основной программы действительно должна быть int main(void), а не только main().

Терминология: «прототип» - это объявление функции, определяющее типы параметров.

int power(int base, int n); /* a declaration that's also a prototype */ 
int power(int, int);   /* likewise */ 
int power();     /* a declaration but not a prototype */ 

(имена параметров необходимы в определении, но необязательно в автономной декларации.)

Как частный случай, прототип для функции без параметров используется (void), так как пустые круглые скобки уже означать не-прототип декларации. Итак, int main(void) является прототипом, но int main() нет.

Непротопические декларации являются «устаревшими», что означает, что теоретически они могут быть удалены из будущего языкового стандарта. Но с 1989 года они устарели, и даже в новом стандарте ISO C 2011 года комитет не счел нужным их удалить.

+0

+1: Спасибо за урок истории. –

+0

Примечание: оставляя тип возвращаемого значения 'main' работает, вероятно, по той же причине, что отказ от работы декларации для OP, в прежние времена C имел правило« неявное int », если тип не указан, подразумевалось неявно быть 'int'. Таким образом, неявный тип 'power' соответствует его реальному типу, поэтому он работал (по-прежнему работает на многих, если не на большинстве компиляторов, из-за обратной совместимости). –

+0

@ DanielFischer: Это верно в C90 и ранее (я специально замалчивал это); правило «неявное int» было сброшено на C99. По-прежнему не рекомендуется использовать это. –

2
int power(int m, int n); 

является декларация power функции в ее прототипе форме. Объявление функции информирует компилятор о числе параметров, которые имеет функция, тип параметров функции и тип возвращаемого значения функции.

В C вы не можете использовать идентификатор функции до того, как оно было объявлено.

+0

«Объявлено, потому что вы не можете вызвать функцию в C до того, как она была объявлена» - не верно. Есть особенности, называющие такие функции, но они легальны (поэтому пример OP работает без прототипа). – jpalecek

+0

@jpalecek Вы могли бы расширить, пожалуйста?Начиная с C99, объявления неявных функций больше не допускаются, а определение функции - это объявление функции, которая включает тело функции. – ouah

+0

@jpalecek «Пример OP работает без прототипа». Ну, без прототипа функции программа OP перестает действовать. – ouah

1

Если вы не включаете эту строку вверху, когда программа достигает power(2,i), основная мощность еще не объявлена. Программы читаются сверху вниз, и, помещая объявление вверху, компилятор знает, что «определение приближается».

2

Это вперед заявление что делает функцию интерфейса общественности как функция используется, прежде чем она на самом деле реализуется ниже main().

Файлы заголовков, которые вы #include предоставляют аналогичную функциональность, предоставляя общедоступный API-интерфейс, но код обычно предоставляется в библиотеке, а не через один и тот же блок компиляции, как здесь, в примере с одним файлом главы K & R.

1

Эта линия является просто прототипом функции. Это форвардная декларация, которая позволяет коду использовать некоторую функцию с этой подписью, которая будет существовать, когда все будет связано друг с другом. Без него функция main() попытается использовать функцию power(), но компилятор еще не знает об этом, так как на самом деле она не определена позже в исходном файле.

0

Эта строка в верхней части, на которую вы ссылаетесь, является прототипом функции. Единственная вещь, в которой она существует, - это то, что компилятор может проверить вашу работу, то есть убедиться, что вы правильно используете эту функцию, передавая правильные типы и количество аргументов. Это все, для чего. Вот почему вы можете удалить его, и код все еще компилируется - все, что вы делаете, удаляя его, удаляет ссылку компилятора, чтобы он не мог проверить вашу работу. И если вы удалите его, тогда есть вероятность, что вы можете передать неправильный тип аргументов и вызвать сложную ошибку времени выполнения или сбой программы. Но оставляя его, позволяет компилятору отмечать такую ​​ошибку во время компиляции, сохраняя при этом некоторое горе. И спасти кого-то горе - это хорошо.

Позже, со стандартом C99, они решили сделать обязательным предоставление прототипа функции (или определить функцию в первую очередь), чтобы код мог компилироваться, что заставило компилятор проверить вашу работу.