Разница между "struct" и "typedef struct" в C++?


В C++, есть ли разница между:

struct Foo { ... };

и

typedef struct { ... } Foo;
8 697

8 ответов:

в C++ есть только тонкая разница. Это пережиток от C, в котором это имеет значение.

стандарт языка C (C89 §3.1.2.3,C99 §6.2.3 и C11 §6.2.3) мандаты отдельных пространств имен для различных категорий идентификаторов, в том числе тег идентификаторы (для struct/union/enum) и обычные идентификаторы (для typedef и другие идентификаторы).

если бы ты только сказал:

struct Foo { ... };
Foo x;

вы получите ошибку компилятора, потому что Foo определяется только в пространстве имен тегов.

вы должны были бы объявить его как:

struct Foo x;

в любое время вы хотите обратиться к Foo, вы всегда должны были бы назвать его struct Foo. Это раздражает быстро, так что вы можете добавить typedef:

struct Foo { ... };
typedef struct Foo Foo;

теперь struct Foo (в пространстве имен тегов) и просто Foo (в обычном пространстве имен идентификаторов) оба ссылаются на одно и то же, и вы можете свободно объявлять объекты типа Foo без struct ключевое слово.


конструкция:

typedef struct Foo { ... } Foo;

- это просто аббревиатура для заявления и typedef.


наконец,

typedef struct { ... } Foo;

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


в C++, все struct/union/enum/class объявления действуют так, как будто они неявно typedef'ed, пока имя не скрыто другим объявлением с тем же именем. Смотрите ответ Майкла Берра для полной информации.

на это DDJ статья, Дэн Сакс объясняет одну небольшую область, где ошибки могут проползти, если вы не набираете свои структуры (и классы!):

если вы хотите, вы можете себе представить, что c++ создает typedef для каждого тега название, например,

typedef class string string;

к сожалению, это не совсем точный. Если бы все было так просто, но это не так. C++ не может генерировать такие для определения типов структуры, объединения или перечисления без введения несовместимости с С.

например, предположим, что программа C объявляет как функцию, так и структуру именованный статус:

int status(); struct status;

опять же, это может быть плохая практика, но это C. В этой программе Статус (by себя) относится к функции; struct статус относится к типу.

если C++ автоматически генерирует определения типов тегов, тогда, когда вы скомпилированная программа на C++, в компилятор будет генерировать:

typedef struct status status;

к сожалению, это имя типа конфликт с именем функции, и программа не будет компилироваться. Это почему C++ не может просто сгенерировать typedef для каждого тега.

в C++ теги действуют так же, как typedef имена, за исключением того, что программа может объявить объект, функцию или перечислитель с тем же именем и та же область, что и тег. В этом случае имя объекта, функции или перечислителя скрывает имя тега. Программа может см. имя тега только по с помощью ключевое слово class, struct, union или перечисление (по мере необходимости) перед имя тега. Имя типа, состоящее из одно из этих ключевых слов последовал тег-это детализированный спецификатор типа. Например, статус структуры и перечисление месяц разрабатываются-тип-спецификаторы.

таким образом, программа C, которая содержит оба:

int status(); struct status;

ведет себя так же, когда компилируется как C++. Только статус имени относится к функция. Программа может ссылаться на тип только с помощью разработан-тип-описатель структуры статус.

так как же это позволяет Багам ползти в программы? Рассмотрим программу в листинг 1. Эта программа определяет класс Foo с конструктором по умолчанию , и оператор преобразования, который преобразует объект foo в char const *. Выражение

p = foo();

в основном должен построить объект foo и примените оператор преобразования. Этот последующий вывод заявление

cout << p << '\n';

должен отображать класс foo, но это нет. Он отображает функцию Foo.

этот удивительный результат происходит потому, что программа включает в себя заголовок lib.ч показано в листинг 2. Этот заголовок определяет функцию с именем foo. Этот имя функции foo скрывает имя класса фу, так что ссылка на фу в основном относится к функции, а не класса. главным образом может относиться к классу только с помощью разработан-тип-описатель, как в

p = class foo();

способ избежать такой путаницы на протяжении всей программы, чтобы добавить после typedef для имени класса фу:

typedef class foo foo;

непосредственно перед или после занятий определение. Этот тип вызывает конфликт между именем типа Foo и имя функции foo (от библиотека), что вызовет Ошибка времени компиляции.

Я не знаю никого, кто на самом деле пишет эти типажи как само собой разумеющееся. Оно требует большой дисциплины. С частота возникновения таких ошибок, как один в листинг 1 - это, наверное, очень маленькие, вы много никогда не наткнетесь эта проблема. Но если ошибка в вашем программное обеспечение может привести к телесным повреждениям, тогда вы должны написать typedefs нет неважно, насколько маловероятна ошибка.

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

еще одно важное отличие:typedefs не может быть объявлено вперед. Так что за вы должны #include файл, содержащий typedef, Что означает все, что #includes ваш .h также включает в себя этот файл, нужен ли он непосредственно или нет, и так далее. Это определенно может повлиять на время сборки на более крупные проекты.

без typedef в некоторых случаях вы можете просто добавить вперед декларации struct Foo; в верхней части вашего , и только #include определение структуры в вашем .

здесь и разница, но тонкие. Взгляните на это так:struct Foo вводит новый тип. Второй создает псевдоним Foo (а не новый тип) для безымянного struct тип.

7.1.3 спецификатор typedef

1 [...]

имя, объявленное с помощью спецификатора typedef, становится именем typedef. В рамках своего заявления, оператор typedef-имя синтаксически эквивалентным ключевому слову и называет тип, связанный с идентификатором в способ, описанный в пункте 8. Таким образом, имя typedef является синонимом другого типа. A typedef-name не вводит новый тип как объявление класса (9.1) или перечисление объявление делает.

8 Если объявление typedef определяет безымянный класс( или перечисление), первое имя typedef, объявленное объявлением чтобы быть этим типом класса (или типом перечисления), используется для обозначения типа класса (или типа перечисления) для связи целей (3.5). [ Пример:

typedef struct { } *ps, S; // S is the class name for linkage purposes

Итак, typedef всегда используется в качестве заполнителя/синонима для другого типа.

вы не можете использовать прямое объявление со структурой typedef.

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

typedef struct{
    int one;
    int two;
}myStruct;

прямое объявление, как это не будет работать:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types

важное различие между "typedef struct" и "struct" в C++ заключается в том, что инициализация встроенного члена в "typedef structs" не будет работать.

// the 'x' in this struct will NOT be initialised to zero
typedef struct { int x = 0; } Foo;

// the 'x' in this struct WILL be initialised to zero
struct Foo { int x = 0; };

структура для создания типа данных. Определение типа установить псевдоним для типа данных.

в C++ нет разницы, но я считаю, что в C это позволит вам объявлять экземпляры структуры Foo без явного выполнения:

struct Foo bar;