Różnica między 'struct ' a' typedef struct ' w C++?

W C++, czy jest jakaś różnica między:

struct Foo { ... };

I:

typedef struct { ... } Foo;
Author: Arsen Khachaturyan, 2009-03-04

8 answers

W C++ jest tylko subtelna różnica. To wstrzymanie od C, w którym robi różnicę.

Standard języka C ( C89 §3.1.2.3, C99 §6.2.3 i C11 §6.2.3) nakazuje oddzielne przestrzenie nazw dla różnych kategorii identyfikatorów, w tym identyfikatory znaczników (dla struct/union/enum) i zwykłe identyfikatory (dla typedef i innych identyfikatorów).

Gdybyś powiedział:

struct Foo { ... };
Foo x;

Dostaniesz błąd kompilatora, ponieważ {[9] } jest zdefiniowany tylko w przestrzeni nazw znaczników.

Musisz zadeklarować to jako:

struct Foo x;

Za każdym razem, gdy chcesz odnieść się do Foo, zawsze musisz to nazwać struct Foo. To robi się irytujące szybko, więc możesz dodać typedef:

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

Teraz struct Foo (w przestrzeni nazw znaczników) i po prostu Foo (w zwykłej przestrzeni nazw identyfikatorów) odnoszą się do tego samego, i możesz dowolnie deklarować obiekty typu Foo Bez struct słowo kluczowe.


Konstrukcja:

typedef struct Foo { ... } Foo;

Jest tylko skrótem od deklaracji i typedef.


Wreszcie,

typedef struct { ... } Foo;

Deklaruje strukturę anonimową i tworzy dla niej typedef. Tak więc, w przypadku tej konstrukcji, nie ma nazwy w przestrzeni nazw tagów, tylko nazwę w przestrzeni nazw typedef. Oznacza to, że również nie może być zadeklarowany terminowo. jeśli chcesz złożyć deklarację forward, musisz podać jej nazwę w znaczniku przestrzeń nazw .


W C++, Wszystkie struct/union/enum/class deklaracje zachowują się tak, jakby były niejawne typedef ' ed, o ile nazwa nie jest ukryta przez inną deklarację o tej samej nazwie. Zobacz odpowiedź Michaela Burra po pełne szczegóły.

 1232
Author: Adam Rosenfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-14 17:08:20

W Ten artykuł DDJ , Dan Saks wyjaśnia jeden mały obszar, w którym mogą się wkradać błędy, jeśli nie wpisujesz swoich struktur (i klas!):

Jeśli chcesz, możesz sobie wyobrazić, że C++ generuje typedef dla każdego tagu nazwa, np.

typedef class string string;

Niestety, nie jest to do końca dokładnie. Chciałbym, żeby to było takie proste., ale tak nie jest. C++ nie potrafi wygenerować takiego typedefs dla struktur, związków lub enum bez wprowadzania niezgodności farmaceutycznych z C.

Na przykład, załóżmy, że program C deklaruje zarówno funkcję, jak i strukturę nazwa statusu:

int status(); struct status;

Znowu, to może być zła praktyka, ale jest C. W tym programie, status (przez siebie) odnosi się do funkcji; struct status odnosi się do typu.

If C++ did automatically generate wpisywać znaczniki, wtedy gdy skompilował ten program jako C++, kompilator generuje:

typedef struct status status;

Niestety, nazwa tego typu będzie konflikt z nazwą funkcji, oraz program nie chce się skompilować. To dlaczego C++ nie potrafi po prostu wygenerować typedef dla każdego tagu.

W C++ znaczniki działają tak jak typedef nazwy, z tym, że program może zadeklarować obiekt, funkcję lub enumerator o tej samej nazwie i ten sam zakres co znacznik. W takim przypadku nazwa obiektu, funkcji lub wyliczenia ukrywa nazwę tagu. Program może odwołaj się do nazwy tagu tylko za pomocą słowo kluczowe class, struct, union lub enum (jako właściwe) przed nazwa znacznika. Nazwa typu składająca się z jednym z tych słów kluczowych, po którym następuje tag jest rozwiniętym specyfikatorem typu. Na przykład, struct status i enum miesiąc są opracowane-Typ-specifiiers.

Tak więc, program C, który zawiera zarówno:

int status(); struct status;

Zachowuje się tak samo, gdy jest skompilowany jako C++. Sama nazwa odnosi się do funkcja. Program może odnosić się do wpisz tylko za pomocą rozwinięta struktura-Typ-specifier status.

Więc jak to pozwala robakom pełzać do programów? Rozważ program w Listing 1 . Program ten definiuje Klasa foo z domyślnym konstruktorem, oraz operator konwersji, który konwertuje obiekt foo na znak const *. Wyrażenie

p = foo();

W main powinien skonstruować obiekt foo i zastosować operator konwersji. Na kolejne polecenie wyjścia

cout << p << '\n';

Powinien wyświetlać klasę foo, ale wyświetla funkcję foo.

Ten zaskakujący wynik występuje, ponieważ program zawiera nagłówek lib.h Wyświetlono w Listing 2 . Ten nagłówek definiuje funkcję o nazwie foo. Na nazwa funkcji Foo ukrywa nazwę klasy foo, czyli odniesienie do foo w main odnosi się do funkcji, nie Klasy. main może odnosić się do klasy tylko przez przy użyciu opracowanego-Typ-specifier, jako w

p = class foo();

Sposób na uniknięcie takiego zamieszania w całym programie jest dodanie następujące typedef dla klasy nazwa foo:

typedef class foo foo;

Bezpośrednio przed lub po zajęciach definicja. Ten typ powoduje konflikt między nazwą typu foo a nazwa funkcji foo (od biblioteka), która wywoła błąd czasu kompilacji.

Nie znam nikogo, kto faktycznie pisze te typedefs oczywiście. To wymaga sporej dyscypliny. Od częstość występowania błędów, takich jak jeden z Listing 1 jest prawdopodobnie ładny małe, wy nigdy nie uciekacie przed ten problem. Ale jeśli błąd w Twoim oprogramowanie może spowodować uszkodzenie ciała, w takim razie należy wpisać typedefs no ważne, jak mało prawdopodobny jest błąd.

Nie wyobrażam sobie, dlaczego ktokolwiek miałby kiedykolwiek chcesz ukryć nazwę klasy za pomocą nazwa funkcji lub obiektu w tym samym zakres jako klasa. Zasady ukrywania w C były błędem i powinny nie zostały rozszerzone na zajęcia w C++. Rzeczywiście, można poprawić błąd, ale wymaga dodatkowego dyscyplina programowania i wysiłek że nie powinno to być konieczne.

 233
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-19 18:22:10

Jeszcze jedna ważna różnica: typedefs nie może być zadeklarowana. Tak więc dla opcji typedef musisz #include plik zawierający typedef, czyli wszystko, co #includejest Twoim .h zawiera również ten plik, niezależnie od tego, czy go bezpośrednio potrzebuje, czy nie, i tak dalej. Może to zdecydowanie wpłynąć na czas budowy większych projektów.

Bez typedef, w niektórych przypadkach możesz po prostu dodać deklarację forward struct Foo; u góry pliku .h, a jedynie #include definicję struktury w .cpp plik.

 66
Author: Joe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-19 18:21:35

Istnieje jest różnica, ale subtelna. Spójrz na to w ten sposób: struct Foo wprowadza nowy typ. Drugi tworzy alias Foo (a nie nowy typ) dla nienazwanego typu struct.

7.1.3 typedef

1 [...]

Nazwa zadeklarowana ze specyfikatorem typedef staje się nazwą typedef. W zakresie swojej deklaracji, a typedef-name jest składniowo odpowiednikiem słowa kluczowego i nazywa Typ związany z identyfikator w sposób opisany w punkcie 8. Nazwa typedef jest więc synonimem innego typu. Typedef-imię nie wprowadza nowego typu tak jak robi to deklaracja klasy (9.1) lub deklaracja enum.

8 jeśli deklaracja typedef definiuje nienazwaną klasę (lub enum), pierwsza nazwa typedef zadeklarowana przez deklarację aby być, że typ klasy (lub typ enum) jest używany do oznaczenia typu klasy (lub typ enum) dla powiązania tylko cele (3.5). [ Przykład:

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

Tak więc typedef Zawsze jest używany jako symbol zastępczy / synonim innego typu.

 33
Author: dirkgently,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-04 22:01:13

Nie można używać deklaracji forward ze strukturą typedef.

Sama struktura jest typem anonimowym, więc nie masz rzeczywistej nazwy do zadeklarowania.

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

Taka deklaracja forward nie zadziała:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types
 10
Author: Yochai Timmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-08-05 09:18:39

Istotną różnicą między 'strukturą typedef' a 'strukturą' w C++ jest to, że inicjalizacja elementów w 'strukturach typedef' nie będzie działać.

// 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; };
 1
Author: user2796283,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-11 13:26:25

Nie ma żadnej różnicy w C++, ale wierzę, że w C pozwoli Ci to zadeklarować instancje struktury Foo bez jawnego działania:

struct Foo bar;
 -3
Author: xian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-04 20:44:20

Struct służy do utworzenia typu danych. Typedef ma na celu ustawienie pseudonimu dla typu danych.

 -3
Author: David Tu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-08 03:06:14