#include <stdio.h>
#define MAX 5
static int data = 10;
int increment(void *);
int increment(void *ptr)
{
int *p = ptr;
static int data =15;
for (int loop=0; loop < MAX; loop++)
{
data++;
}
return data;
}
int main(void)
{
printf("%d\n", data++);
static int data = 25;
for (int loop=0; loop < MAX ; loop++)
{
data++;
}
printf("%d\n", data++);
data = increment(&data);
printf("%d\n", data++);
return 1;
}
Я понимаю, что статика остается в памяти до конца программы. Тогда в приведенном выше коде есть глобальный static int data
и такой же static int data
в main. Я понимаю, что функция Increment имеет локальную область действия.
По моему мнению, это должно давать множественную ошибку определения. Но этого не произошло. Почему?
Как программа определяет, что здесь я должен взять глобальный data
, а здесь я должен взять основной data
?
Наличие переменной с тем же именем, что и у другой (в другой области видимости), не является ошибкой. Язык это позволяет. Хотя обычно это признак проблемы.
На самом деле, мне следовало написать в своем комментарии выше область действия блока, а не область действия функции.
Как упоминалось другими, C позволяет объявлять переменные с одним и тем же именем в разных областях. Это то, что позволяет вам использовать переменные loop
в разных областях видимости, но также если это делается в одной и той же функции. Переменные, объявленные в более глубоких вложенных областях, скрывают переменные, объявленные во внешних областях.
область видимости, видимость и срок службы различны. Оба имеют время жизни в течение всего времени выполнения программы, но один имеет глобальную область, а другой - внутри основного/инкрементного. Переменная становится видимой с момента ее объявления до конца области видимости. Переменная, объявленная во внутренней области, скрывает переменную, объявленную с тем же именем в любой внешней области.
Из C17, 6.2.1 (Объем идентификаторов), параграф 4:
… Если идентификатор обозначает два разных объекта в одном пространстве имен, области действия могут перекрываться. Если это так, область действия одного объекта (внутренняя область) закончится строго перед областью действия другого объекта (внешняя область). Во внутренней области идентификатор обозначает объект, объявленный в внутренний объем; сущность, объявленная во внешней области, скрыта (и не видна) во внутренней области.
В коде ОП есть три разные переменные static int data
с разными областями действия.
increment
и имеет область действия блока, простирающуюся от точки объявления до конца содержащего блока. В этой области локальная переменная имеет внутреннюю область действия, а глобальная переменная имеет внешнюю область действия идентификатора (внутри пространства имен). Переменная с внешней областью скрыта внутренней областью, поэтому единственный способ получить к ней доступ — через указатель или вызов функции, в области которой находится скрытая переменная.main
и имеет область действия блока, простирающуюся от точки объявления до конца содержащего блока. Опять же, переменная с внешней областью скрыта внутренней областью.Использование data
в функции main
перед локальным объявлением static int data
обозначает глобальную переменную data
с областью действия файла. Другие варианты использования data
внутри функции main
после локального объявления static int data
обозначают локальную переменную data
с областью действия блока.
Область файла
static int data
скрывается областью функцииstatic int data
с момента объявления области функции и далее. Это разные переменные.