Почему я не получил сообщение об ошибке множественного определения?

#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?

Область файла static int data скрывается областью функции static int data с момента объявления области функции и далее. Это разные переменные.

Ian Abbott 08.07.2024 13:21

Наличие переменной с тем же именем, что и у другой (в другой области видимости), не является ошибкой. Язык это позволяет. Хотя обычно это признак проблемы.

pmacfarlane 08.07.2024 13:23

На самом деле, мне следовало написать в своем комментарии выше область действия блока, а не область действия функции.

Ian Abbott 08.07.2024 13:30

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

Some programmer dude 08.07.2024 13:41

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

Jean-Baptiste Yunès 08.07.2024 16:42
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Из C17, 6.2.1 (Объем идентификаторов), параграф 4:

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

В коде ОП есть три разные переменные static int data с разными областями действия.

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

Использование data в функции main перед локальным объявлением static int data обозначает глобальную переменную data с областью действия файла. Другие варианты использования data внутри функции main после локального объявления static int data обозначают локальную переменную data с областью действия блока.

Другие вопросы по теме