#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 Отсутствие связи означает, что она локальна в области, в которой она объявлена. И вы не можете иметь функции внутри других функций, что делает невозможным отсутствие связи. Функция может иметь только внешнюю или внутреннюю связь.