Чому ви використовуєте typedef, коли оголошуєте enum в C ++?


183

Я не писав жодного C ++ років і зараз намагаюся повернутися до нього. Потім я перебіг це і подумав про те, щоб відмовитись:

typedef enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

Що це? Чому typedefтут використовується ключове слово? Чому назва TokenTypeвідображається двічі в цій декларації? Чим семантика відрізняється від цього:

enum TokenType
{
    blah1 = 0x00000000,
    blah2=0x01000000,
    blah3=0x02000000
};

Відповіді:


156

В C, оголосивши перелік, перший спосіб дозволяє вам використовувати його так:

TokenType my_type;

Якщо ви використовуєте другий стиль, ви будете змушені оголосити свою змінну так:

enum TokenType my_type;

Як зазначають інші, це не має значення у C ++. Я здогадуюсь, що або людина, яка написала це, по суті є програмістом C, або ви компілюєте код C як C ++. У будь-якому випадку це не вплине на поведінку вашого коду.


12
Ваше запитання правильне лише для C, але не для C ++. У C ++ переліки та структури можуть використовуватися безпосередньо так, ніби був typedef.
Девід Родрігес - дрибес

7
Так, але це відповідає на реальне запитання, яке було насправді про "що це навіть означає?"
BobbyShaftoe

Так це технічно typedef чи enum?
Miek

5
Це обоє. Можна також сказати: enum TokenType_ {...}; typedef enum TokenType_ TokenType;
Райан Фокс

Відповідь повна, але я вважаю, що справа в тому, що TokenType; після оголошення enum - це те, що оголошує ім'я типу. Отже, відповідь не на 100% закінчена. Об'явивши "перший спосіб", ВІДПОВІДНО перераховується перелік і нове ім'я типу, яке є перерахунком в одній крапці синтаксису. Тож відповідь була корисною, але я думаю, можна було б трохи покращити. Можливо, я був занадто суворий, щоб проголосувати. Тож я все-таки відмовився від цього. Якби я був справді впевнений у собі, я б взявся за зміну / покращення відповіді ... але це дуже хороший анс
Росс

97

Це надбання C, якщо ви робите:

enum TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
};

вам доведеться використовувати це, роблячи щось на кшталт:

enum TokenType foo;

Але якщо ви це зробите:

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

Ви зможете заявити:

TokenType foo;

Але в C ++ ви можете використовувати лише колишнє визначення та використовувати його так, як якщо б воно було в C typedef.


1
Те, що ви говорите, вірно в C. Це неправда в C ++.
Джонатан Леффлер

49
Чи не те, що я сказав у своєму останньому реченні?
мат

2
@mat Я підтримав ваш коментар щодо останнього речення, але, справедливо кажучи, він погано сформульований і заплутаний.
AR

20

Вам не потрібно цього робити. У C (не C ++) вам потрібно було використовувати enum Enumname для позначення елемента даних переліченого типу. Щоб спростити вам було дозволено визначення типу у його до одного типу даних ім'я.

typedef enum MyEnum { 
  //...
} MyEnum;

Дозволено функції, що приймають параметр enum, визначати як

void f( MyEnum x )

замість довшого

void f( enum MyEnum x )

Зауважте, що ім'я набору типу не потрібно дорівнювати імені перерахунку. Те саме відбувається і з конструкціями.

З іншого боку, для C ++ це не потрібно, оскільки до переліків, класів та структур можна отримати доступ безпосередньо до типів за їх назвами.

// C++
enum MyEnum {
   // ...
};
void f( MyEnum x ); // Correct C++, Error in C

Насправді я думаю, що це може бути кращою відповіддю, ніж загальноприйнята, оскільки це чітко пояснює "чому" це інакше.
Ross Youngblood

11

У C це гарний стиль, тому що ти можеш змінити тип на щось, крім ентума.

typedef enum e_TokenType
{
    blah1   = 0x00000000,
    blah2   = 0X01000000,
    blah3   = 0X02000000
} TokenType;

foo(enum e_TokenType token);  /* this can only be passed as an enum */

foo(TokenType token); /* TokenType can be defined to something else later
                         without changing this declaration */

У C ++ ви можете визначити enum, щоб він склався як C ++ або C.


Ви не хочете сказати In C++ you can *typedef* the enum so that it will compile as C++ or C.? Ви сказали: In C++ you can define the enum so that it will compile as C++ or C.Зверніть увагу, як я змінив вас defineна typedef. Ну ... Я вважаю , typedefING є визначальним.
Габріель Стейплз

6

Голдовер від C.


Не знаю, що "ранній" кваліфікатор є відповідним; Ви все одно напишете це в C, якщо хочете використовувати ім'я типу без префікса enum.
Джонатан Леффлер

1
правда. Я його видалю. Я довго не слідкував за специфікацією С. Я був лінивий, щоб перевірити відмінності c / c ++ ... -1 для мене.
Тім

6

Деякі люди кажуть, що у C немає просторів імен, але це технічно не правильно. Її три:

  1. Ключові слова ( enum, unionіstruct )
  2. Мітки
  3. (все інше)

typedef enum { } XYZ; оголошує анонімне перерахування та імпортує його у глобальний простір імен разом з іменем XYZ .

typedef enum ABC { } XYZ;оголошує ABCперелічення, назване у просторі імен тегів, а потім імпортує його у глобальний простір імен якXYZ .

Деякі люди не хочуть турбуватися з окремими просторами імен, тому вони набирають все. Інші ніколи не вводять ключ, оскільки вони хочуть простору імен.


Це не зовсім точно. структури, союзи та перерахунки посилаються на ім'я тегів (крім анонімних, як ви згадували). Існують окремі простори імен для типів і тегів. Ви можете мати тип із таким самим іменем, що і тег, і скласти штраф. Однак, якщо enum має той самий тег, що і структура, це помилка компіляції саме так, як було б 2 структури або 2 перерахунки з тим же тегом. Ви також забуваєте, що мітки для goto - це окремий простір імен. Мітка може бути тим самим іменем, що і тег чи ідентифікатор, але не тип, і ідентифікатор може мати те саме ім'я, що і тег, але не тип.
Багатий Ян

3

Це щось старе, але все одно, я сподіваюся, ви оціните посилання, яке я збираюся набрати, як я оцінив його, коли я натрапив на нього раніше цього року.

Ось воно . Я повинен процитувати пояснення, яке завжди в мене на увазі, коли мені доведеться зрозуміти деякі неприємні типи:

У деклараціях змінних введені імена є екземплярами відповідних типів. [...] Однак, коли typedefключове слово передує декларації, введені назви є псевдонімами відповідних типів

Як багато хто раніше говорив, немає потреби використовувати typedefs, що декларують перерахунки в C ++ . Але це пояснення синтаксису typedef! Я сподіваюся, що це допомагає (напевно, це не ОП, адже минуло майже 10 років, але будь-хто, хто намагається зрозуміти подібні речі).


1

У деяких посібниках з кодексу С вважається, що версія typedef віддається перевазі "чіткість" та "простота". Я не згоден, тому що typedef обтяжує реальну природу заявленого об'єкта. Насправді я не використовую typedefs, тому що при оголошенні змінної C я хочу зрозуміти, що саме є об'єктом. Цей вибір допомагає собі швидше запам'ятати, що насправді робить старий фрагмент коду, і допоможе іншим при збереженні коду в майбутньому.


1

Дійсною відповіддю на питання "чому" (яке дивно ігнорується існуючими відповідями вище цього старого питання) є те, що ця enumдекларація, ймовірно, розташована у файлі заголовка, який призначений для компіляції як C, так і C ++ (тобто включені як в C, так і в C ++-файли реалізації). Мистецтво писати такі заголовкові файли покладається на здатність автора вибирати мовні функції, які мають належне сумісне значення для обох мов.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.