Информатика и технология программирования

       

Области действия функций


Имя функции является объектом, который также имеет определенную область действия -ту часть программы, из которой она может быть вызвана. Существуют всего два варианта областей действия:



-внешние функции: доступны во всех модулях программы;



-статические функции: доступны только в модуле, в котором они определены.

Все функции по умолчанию являются внешними. Это значит, что определенная стандартным образом функция может быть вызвана из любого другого модуля программы. При этом в модуле, в котором осуществляется вызов, она должна быть объявлена. Объявление внешней функции представляет собой заголовок функции, предваренный словом extern .

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

.


Файл a.c Файл b.c

.


объявление функции в объявление внешней
собственном модуле функции
char *f(int,int); extern char *f(int,int);

.


область действия область действия
... f(10,n) ... ... f(15,m) ...
определение функции
char *f(int n1, int n2)
{ ... тело функции ... }

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

.


Обычное объявление Объявление по прототипу
int strcmp(); int strcmp(char* ,char*);
char getch(); char getch(void);



Статические функции имеют определение обычной внешней функции, предваренное словом static . Область действия такой функции не распространяется за пределы текущего модуля, извне обратиться к ним нельзя. Такие функции предназначены для создания собственных служебных функций модуля с тем, чтобы их имена не вступали в конфликт с такими же именами функций в других модулях.


В "классическом" Си имеет место одно очень важное умолчание. Если производится вызов функции, ранее не определенной и не объявленной, то транслятор по умолчанию считает ее внешней с типом результата int , автоматически добавляя объявление вида:

extern int f();



Такое умолчание приводит к нескольким достаточно распространенным ошибкам:




-если программист по ошибке указывает вызов функции с неправильным именем, то при трансляции ошибка, как правило, не возникает, но при этом компоновщик не находит данное имя в собственных библиотеках. Ошибка, таким образом, переносится на этап компоновки. Например,
pintf("%d %d\n",a,b) приводит к успешной трансляции, но к ошибочной компоновке программы в связи с отсутствием функции pintf ;


-если вызов функции в модуле выполняется до ее определения, то по умолчанию она также объявляется в точке ее вызова. Это может привести к конфликту типов результата в месте ее последующего определения. Особенно это касается "любителей" располагать
функцию main в начале модуля:

void main()
{ // по умолчанию объявляются как

f(); // extern int f();

g(); // extern int g();

}
void f() // конфликт типов результата

{ // int и void в объявлении

} // и определении функции




Такую ошибку можно исключить предварительным объявлением функции в любом месте перед ее вызовом:



void f();








-если используется библиотечная функция, которая возвращает не целый результат, то отсутствие ее объявления приводит к тому, что возникает расхождение между ожидаемым транслятором по умолчанию типом int и реально возвращаемым типом (например,
char* или double ). Если эти результаты имеют одну размерность, то, как правило, ошибки не происходит. В противном случае возвращаемое значение "усекается" или "расширяется" до int и становится неопределенным. В приведенном ниже примере результат типа double "усекается" (но не преобразуется) до int , а затем опять переводится в тип double . Ошибка связана с отсутствием объявления функции sin:





// отсутствует объявление extern double sin();

double y; y = sin(1.0);






В следующем примере размерность указателя, возвращаемой функцией malloc в зависимости от текущей модели памяти будет равна размерности int или
long . Это приведет к тому, что при отсутствии объявления функции в одних моделях памяти она будет работать, а в других -нет:



// отсутствует объявление extern void *malloc();

double *p; p = malloc(sizeof(double));



Исключить такие ошибки можно, заранее объявляя библиотечные функции. Такие объявления имеются в заголовочных файлах, которые необходимо включать в текст модуля директивой &#35
include , в наших примерах это:

&#35include &#60alloc.h&#62
&#35include &#60math.h&#62


Содержание раздела