Вопрос

В C ++ есть ли какая-либо разница между:

struct Foo { ... };

и

typedef struct { ... } Foo;
Это было полезно?

Решение

В 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- эд, до тех пор, пока это имя не скрыто другим объявлением с тем же именем.Видишь Ответ Майкла Берра для получения более подробной информации.

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

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

  

Если хотите, можете представить, что C ++   генерирует typedef для каждого тега   имя, например

typedef class string string;
     

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

     

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

int status(); struct status;
     

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

     

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

typedef struct status status;
     

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

     

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

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

p = foo();
     

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

     

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

cout << p << '\n';
     

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

p = class foo();
     

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

     

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

typedef class foo foo;
     

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

<*>      

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

     

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

Я не могу представить, почему кто-то когда-либо   хотите скрыть имя класса с   функция или объект

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

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

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

  

7.1.3 Спецификатор определения типа

     

1 [...]

     

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

     

8 Если объявление typedef определяет безымянный класс (или enum), первое имя typedef, объявленное объявлением   быть таким типом класса (или типом enum) используется для обозначения типа класса (или типа enum) для связи   только для целей (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 - установить псевдоним для типа данных.

Важное различие между '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;
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top