Будет ли функция, объявленная внутри main(), иметь внешнюю связь или никакой связи?

#c #function #external #extern #linkage

#c #функция #внешняя #внешний #связь

Вопрос:

Смотрите следующий код:

 /* first file */

int i; /* definition */
int main () {
  void f_in_other_place (void);   /* declaration */
  i = 0
  return 0;
}
/* end of first file */


/* start of second file */

extern int i; /* declaration */
void f_in_other_place (void){   /* definition */
  i  ;
}
/* end of second file */
  

Я знаю, что внешние объекты имеют external связь, а внутренние объекты имеют none связь ( extern на мгновение игнорируя). Теперь, если я говорю о функции f_in_other_place() , она объявлена внутри функции main . Так будет ли идентификатор для нее обрабатываться как внутренний объект? Если да, то она должна иметь none связь, но, как видно из программы, эта функция ссылается на свое определение во втором файле, которое показывает, что идентификатор для него ведет себя как объект со external связью. Итак, я не понимаю, имеет ли этот идентификатор здесь external связь или none связь?

Теперь, перейдя к extern ключевому слову, я где-то читал, что объявление функции неявно содержит префиксы extern . Итак, даже если я явно не указал extern идентификатор этой функции, станет ли идентификатор моей функции по умолчанию объектом со external связью и областью действия внутри main() ? Пожалуйста, поправьте меня, если я иду в неправильном направлении.

Комментарии:

1. Связь — это свойство идентификаторов, а не функций или объектов. Правильное их различение может помочь в понимании концепций.

Ответ №1:

Я знаю, что внешние объекты имеют внешнюю связь, а внутренние объекты не имеют никакой связи

Я думаю, что под термином «внутренние объекты» вы подразумеваете объекты, объявленные в областях блоков.

Что касается этого объявления

 int i; /* definition */
  

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

 int i; /* definition */
int i; /* definition */
int i; /* definition */
  

Компилятор генерирует так называемое предварительное определение этой переменной в конце единицы преобразования, инициализируя ее нулем.

Что касается объявления функции в main, то в соответствии со стандартом C (6.2.2 Ссылки идентификаторов)

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

и

4 Для идентификатора, объявленного с помощью спецификатора класса хранения extern в области видимости, в которой видно предыдущее объявление этого идентификатора, 31) если предыдущее объявление указывает внутреннюю или внешнюю связь, связь идентификатора при последующем объявлении такая же, как и связь, указанная в предыдущем объявлении. Если предыдущее объявление не отображается или если в предыдущем объявлении не указано никакой связи, то идентификатор имеет внешнюю связь.

Итак, это объявление функции в main

 void f_in_other_place (void);
  

эквивалентно

 extern void f_in_other_place (void);
  

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

Если, например, в области видимости файла перед main будет объявление с ключевым static словом like

 static void f_in_other_place (void);
  

тогда функция, объявленная в main, будет иметь внутреннюю связь.

Комментарии:

1. Понял. Только одно сомнение. Стандарт гласит: для идентификатора, объявленного с помощью спецификатора класса хранения extern в области видимости, в которой видно предыдущее объявление этого идентификатора. В моей программе не будет такой области видимости main() ? Вы говорите о области действия файла. Разве область действия файла не отличается от области действия main ?

2. @LocalHost Да, область действия функции, объявленной в main, является самой внешней областью действия main, и в этой области предыдущее объявление функции не отображается. То есть объявление функции в main не переопределяет функцию с тем же типом во внешней области относительно области main .

3. Я не понимаю. Допустим, если static void f_in_other_place (void); это объявление присутствует перед моим main() объявлением, будет ли оно видно в моем более позднем объявлении? и чем это изменит связь internal . Я правильно понимаю??

4. @LocalHost Это объявление в области видимости файла отображается в main, потому что ни одно другое объявление не объявляет этот идентификатор повторно до объявления функции в main . Таким образом, объявление в main объявляет ту же функцию, что и объявление в области файла.

Ответ №2:

Из этой ссылки на связь:

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

[Выделение мое]

Не имеет значения, где вы объявляете функцию, она всегда будет иметь внешнюю связь.

Комментарии:

1. Так это правда, что все объявления имеют неявный extern префикс? и вы никак не можете заставить функцию иметь none связь?

2. @LocalHost Отсутствие связи означает, что она локальна в области, в которой она объявлена. И вы не можете иметь функции внутри других функций, что делает невозможным отсутствие связи. Функция может иметь только внешнюю или внутреннюю связь.