Живет ли объявление структуры после области, в которой оно было объявлено, если область была другим определением структуры? - PullRequest
0 голосов
/ 11 мая 2019

Итак, я получил следующее предупреждение после внесения некоторых изменений в код:

warning: declaration of 'struct Thing' will not be visible
      outside of this function

Этот отличный ответ прояснил проблему.

Затем я озадачился чем-то другим.Оказалось, что перед ошибкой была моя программа:

struct OtherThing {
    struct Thing* t; // <-- struct Thing declared here
};

void func(struct Thing* t);

int main(void) {
  return 0;
}

И эта программа выдает предупреждение:

struct OtherThing {
    int t; // <-- struct Thing no-longer declared here
};

void func(struct Thing* t);

int main(void) {
  return 0;
}

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

Но - объявление struct, которое объявлено в другом struct определение продолжает жить после окончания '}' ?

Верно ли мое понимание?Если это так, то это неправда, что одни и те же правила определения области действия применяются для struct объявлений и обычных переменных (в отличие от заявления, сделанного в связанном ответе).Какая логика стоит за этим дизайном?

1 Ответ

1 голос
/ 11 мая 2019

Живет ли объявление структуры после области, в которой оно было объявлено, если область была другим определением структуры?

Этот вопрос имеет ложную предпосылку. Определение структуры не является областью действия, поэтому область действия объявления структуры не может быть объявлением вложенной структуры. Область действия должна быть областью действия файла, областью прототипа функции или областью блока.

Объявление структуры не формирует область видимости - фигурные скобки, которые связывают объявление структуры, не являются блоком, связанным с областью видимости. Таким образом, объявление структуры внутри объявления структуры действует аналогично объявлению нераскрытой структуры - тег, объявленный для структуры, виден вне ограждающей структуры.

Учтите это:

struct Outer
{
    struct Inner *Member;
};

Это объявляет внешние и внутренние теги структуры. Оба имеют одинаковую область видимости (за исключением небольшого различия в начальной точке; область видимости каждого начинается там, где появляется его имя). Если они появляются вне какой-либо функции, они имеют область видимости файла. Если они появляются внутри блока (составной оператор с использованием {}), они имеют область видимости блока. Если они появляются внутри объявлений параметров функции, они имеют область действия параметра функции (но это обычно не полезно для структур). Обратите внимание, что составной оператор представляет собой список операторов внутри { и }. Скобки, используемые в объявлении структуры, не образуют составной оператор.

Может сложиться впечатление, что область действия ограничена объявлением структуры, поскольку имена элементов структуры, такие как Member, не могут использоваться вне структуры. Но это по другой причине: имена членов структуры находятся в отдельных пространствах имен. Каждая структура имеет свое собственное пространство имен, а имена ее членов находятся в своем пространстве имен. Напротив, существует только одно пространство имен для всех тегов структуры / объединения / перечисления (и одно пространство имен для всех обычных идентификаторов и одно пространство имен для всех goto меток).

Какая логика стоит за этим дизайном?

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

Связывание структурных тегов (или, аналогично, определений типов) потребовало бы изменений в языке. Вам понадобится способ указать, на какую структуру ссылается тег. C ++ делает это с помощью синтаксиса ::. Я не могу говорить об истории того, рассматривались ли такие изменения для C, но мы по крайней мере видим, что это повлекло бы за собой определенные затраты и, вероятно, нарушило бы существующий код - любой код, ссылающийся на тег структуры, объявленный внутри другой структуры, имел бы пришлось изменить, чтобы включить новую спецификацию структуры, на которую он ссылался.

...