Когда мне не нужен typedef? - PullRequest
       11

Когда мне не нужен typedef?

5 голосов
/ 05 февраля 2009

Я столкнулся с чтением кода

typedef enum eEnum { c1, c2 } tagEnum;

typedef struct { int i; double d; } tagMyStruct;

Я слышал слухи, что эти конструкции датируются C. В C ++ вы можете легко написать

enum eEnum { c1, c2 };
struct MyStruct { int i; double d; };

Это правда? Когда вам нужен первый вариант?

Ответы [ 5 ]

10 голосов
/ 05 февраля 2009

Во-первых, оба объявления допустимы как на C, так и на C ++. Однако в Си они имеют немного другую семантику. (В частности, способ, которым вы ссылаетесь на структуру позже, меняется).

Ключевым понятием, которое нужно понять, является то, что в C структуры существуют в отдельном пространстве имен. Все встроенные типы, а также определения типов существуют в пространстве имен «по умолчанию». То есть, когда я набираю int, компилятор проверяет только это пространство имен «по умолчанию». Если я наберу «tagMyStruct», как в вашем примере, компилятор также проверяет только это одно пространство имен. Но в зависимости от того, какой тип объявления вы используете, структура может не существовать в этом пространстве имен.

Структуры разные и существуют в отдельном пространстве имен. Поэтому, если я сделаю следующее заявление:

struct mystruct {};

Я могу не просто называть это mystruct. Вместо этого я должен указать, что я хочу, чтобы mystruct существовал в пространстве имен struct:

void foo(struct mystruct bar); // Declare a function which takes a mystruct as its parameter

Который становится немного многословным и неловким в долгосрочной перспективе. Вместо этого вы можете ввести его в пространство имен по умолчанию:

typedef struct mystruct mystruct; // From now on, 'mystruct' in the normal namespace is an alias for 'mystruct' in the struct namespace

и теперь моя функция может быть объявлена ​​простым способом:

void foo(mystruct bar);

Итак, ваш первый пример просто объединяет эти два шага: объявите структуру и поместите псевдоним в обычное пространство имен. И, конечно же, поскольку мы все равно определяем его, нам не нужно «оригинальное» имя, поэтому мы можем сделать структуру анонимной. Итак, после вашей декларации

typedef struct { int i; double d; } tagMyStruct;

у нас есть структура без имени, которая была определена с помощью typedef в tagMyStruct в пространстве имен по умолчанию.

Вот как С относится к этому. Оба типа объявлений являются допустимыми, но один не создает псевдоним в пространстве имен «по умолчанию», поэтому вы должны использовать ключевое слово struct каждый раз, когда ссылаетесь на тип.

В C ++ отдельное пространство имен struct не существует, поэтому они означают одно и то же. (но более короткая версия предпочтительна).

Редактировать Просто чтобы прояснить, нет, C не имеет пространств имен. Не в обычном смысле. C просто помещает идентификаторы в одно из двух предопределенных пространств имен. Имена структур (и, как я помню, перечисления) помещаются в один, а все остальные идентификаторы - в другой. Технически, это пространства имен, потому что они являются отдельными «контейнерами», в которые помещаются имена, чтобы избежать конфликтов, но они определенно не являются пространствами имен в смысле C ++ / C #.

10 голосов
/ 05 февраля 2009

В C, если вы должны были написать

struct MyStruct { int i; double d; };

всякий раз, когда вы хотите сослаться на этот тип, вы должны указать, что говорите о структуре:

struct MyStruct instanceOfMyStruct;
struct MyStruct *ptrToMyStruct;

С версией typedef:

typedef struct { int i; double d; } tagMyStruct;

вам нужно только написать:

tagMyStruct instanceOfMyStruct;
tagMyStruct *ptrToMyStruct;

Другое большое преимущество с версией typedef состоит в том, что вы можете ссылаться на структуру одинаково как в C, так и в C ++, тогда как во второй версии на них ссылаются иначе, чем в C ++.

1 голос
/ 05 февраля 2009

Это просто стенография.

Во втором случае, чтобы объявить структуру, с которой вы сделаете это:

struct MyStruct a;

В первом варианте вы бы сделали это с:

tagMyStruct a;
0 голосов
/ 05 февраля 2009

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

0 голосов
/ 05 февраля 2009

Второй вариант также существует в C.

Вы используете первый вариант всякий раз, когда хотите назвать свой тип, например ::

tagEnum myFunc(tagMyStruct * myArg);
...