Вся C-программа необязательно компилируется одновременно; исходный текст программы может храниться в нескольких файлах и ранее скомпилированные процедуры могут загружаться из библиотек. Связь между функциями может осуществляться как через явные обращения, так и в результате манипулирования с внешними данными.
Поэтому следует рассмотреть два вида областей действия: во-первых, ту, которая может быть названа лексической областью действия идентификатора и которая по существу является той областью в программе, где этот идентификатор можно использовать, не вызывая диагностического сообщения "неопределенный идентификатор"; и во-вторых, область действия, которая связана с внешними идентификаторами и которая характеризуется правилом, что ссылки на один и тот же внешний идентификатор являются ссылками на один и тот же об'ект.
Лексическая область действия идентификаторов, описанных во внешних определениях, простирается от определения до конца исходного файла, в котором он находится. Лексическая область действия идентификаторов, являющихся формальными параметрами, распространяется на ту функцию, к которой они относятся. Лексическая область действия идентификаторов, описанных в начале блока, простирается до конца этого блока. Лексической областью действия меток является та функция, в которой они находятся.
Поскольку все обращения на один и тот же внешний идентификатор обращаются к одному и тому же об'екту (см. п. 20.2), компилятор проверяет все описания одного и того же внешнего идентификатора на совместимость; в действительности их область действия распространяется на весь файл, в котором они находятся.
Во всех случаях, однако, есть некоторый идентификатор, явным образом описан в начале блока, включая и блок, который образует функцию, то действие любого описания этого идентификатора вне блока приостанавливается до конца этого блока.
Напомним также (п. 17.5), что идентификаторы, соответствующие обычным переменным, с одной стороны, и идентификаторы, соответствующие членам и ярлыкам структур и об'единений, с другой стороны, формируют два непересекающихся класса, которые не вступают в противоречие. Члены и ярлыки подчиняются тем же самым правилам определения областей действия, как и другие идентификаторы. Имена, специфицируемые с помощью typedef, входят в тот же класс, что и обычные идентификаторы. Они могут быть переопределены во внутренних блоках, но во внутреннем описании тип должен быть указан явно:
typedef float distance; ... { auto int distance; ...Во втором описании спецификатор типа int должен присутствовать, так как в противном случае это описание будет принято за описание без описателей с типом distance (прим. Автора: согласитесь, что лед здесь тонок.).
Если функция ссылается на идентификатор, описанный как extern, то гдe-то среди файлов или библиотек, образующих полную программу, должно содержаться внешнее определение этого идентификатора. Все функции данной программы, которые ссылаются на один и тот же внешний идентификатор, ссылаются на один и тот же об'ект, так что следует позаботиться, чтобы специфицированные в этом определении тип и размер были совместимы с типом и размером, указываемыми в каждой функции, которая ссылается на эти данные.
Появление ключевого слова extern во внешнем определении указывает на то, что память для описанных в нем идентификаторов будет выделена в другом файле. Следовательно, в состоящей из многих файлов программе внешнее определение идентификатора, не содержащее спецификатора extern, должно появляться ровно в одном из этих файлов. Любые другие файлы, которые желают дать внешнее определение этого идентификатора, должны включать в это определение слово extern. Идентификатор может быть инициализирован только в том описании, которое приводит к выделению памяти.
Идентификаторы, внешнее определение которых начинается со слова static, недоступны из других файлов. Функции могут быть описаны как static.