Подтвердить что ты не робот

Тег структуры в C vs С++

Я написал следующую простую программу и скомпилировал ее на компиляторе gcc

#include <stdio.h>
typedef int i;
void foo()
{
    struct i {i i;} i;
    i.i = 3;
    printf("%i\n", i.i);
}
int main() { foo(); }

Он компилируется и отлично работает в C. (см. живое демо здесь) Но это не скомпилировано в С++. Компилятор С++ предоставляет следующие сообщения об ошибках.

prog.cc: In function 'void foo()':
prog.cc:5:17: error: field 'i' has incomplete type 'foo()::i'
     struct i {i i;} i;
                 ^
prog.cc:5:12: note: definition of 'struct foo()::i' is not complete until the closing brace
     struct i {i i;} i;

Смотрите демо-версию здесь

Я не мог найти правила относительно этого в стандартах C и С++. Почему он компилируется в C, но не на С++? Что говорит об этом стандарт? Я очень хорошо знаю, что C и С++ - разные языки, имеющие разные правила, но мне любопытно узнать о точных правилах.

4b9b3361

Ответ 1

Разница между C и С++ заключается в следующем. В C член данных i рассматривается как имеющий тип int, потому что если вы хотите, чтобы у него был тип struct i, тогда вам нужно написать struct i i с указанием ключевого слова struct до i.

Структурные теги находятся в собственном пространстве имен по сравнению с пространством имен других переменных.

В соответствии со стандартом C (6.2.3. Идентификационные пространства идентификаторов)

1 Если отображается более одного объявления определенного идентификатора в любой точке единицы перевода, синтаксический контекст disambigutates использует, которые относятся к различным сущностям. Таким образом, существуют отдельные пространства имен для различных категорий идентификаторов, как следующим образом:

- имена меток (неоднозначно синтаксис объявления метки и использование);

- теги структур, объединений и перечислений (неоднозначно после any32) ключевых слов struct, union или enum);

- члены структур или союзов; каждая структура или объединение имеет отдельное пространство имен для своих членов (неоднозначно по типу выражение, используемое для доступа к элементу через. или → );

- все другие идентификаторы, называемые обычными идентификаторами (объявленными в обычные деклараторы или константы перечисления).

Что касается С++, то внутри определения структуры имя структуры скрывает имя typedef, а компилятор выдает ошибку. В С++ существует отдельная область класса.

Например, в С++ (поиск по имени 3.4) записано

3 Введенное имя класса класса (раздел 9) также рассматривается быть членом этого класса для целей скрытия имени и поиск.

и (3.4.1 Поиск неквалифицированного имени)

7 Имя, используемое в определении класса X вне члена тело функции или определение вложенного класса29 должно быть объявлено в одном из следующие способы: - перед его использованием в классе X или быть членом базовый класс X (10.2) или...

Таким образом, введенное имя класса скрывает имя typedef в определении класса.

Учесть, что вне определения класса имя класса можно скрыть одним и тем же именем объекта. Таким образом, если вы хотите объявить объект класса в этой области, вы должны использовать его выработанное имя, например

int i;

struct i {};

//...

struct i obj;