W C i C++:
struct A; // deklaracja (zwana też czasami "deklaracją wyprzedzającą" albo "zapowiadającą", chociaż widziałem też użycie słowotworu "predeklaracja")
struct A { ... }; // definicja
Możemy sobie teraz zdefiniować zmienne:
struct A obj; // C i C++
A obj; // C++
W C - dla wygody - możesz sobie zrobić alias za pomocą typedef
, żeby nie pisać ciągle tego struct
:
struct A { ... };
typedef struct A A;
A obj; // OK!
struct A obj; // OK!
W C++ jest to zbędne, bo struct A
już wprowadza nazwę A
do przestrzeni nazw. ;)
Tego typedefa można sklecić razem z definicją typu:
typedef struct A { ... } A;
A obj; // OK!
struct A obj; // OK!
Można jeszcze krócej, używając anonimowej struktury, ale trzeba pamiętać, że pozbawimy się pewnych możliwości:
typedef struct { ... } A;
A obj; // OK!
struct A obj; // FAIL!
[edit: Powyższe zwykle nie jest mile widziane, ale jest smutną rzeczywistością w niejednym projekcie. Wiele "można", nie wszystko "powinno się". ;) ]
struct A; // deklaracja
void foo(struct A* p); // deklaracja będąca prototypem (w C deklaracja i prototyp to dwie różne sprawy, ale to sprawy techniczne i wykraczające poza ten temat)
typedef struct A { // definicja
int x;
} A;
void foo(A* p) { // definicja
p->x = 42;
}
// ale nie da się napisać deklaracji anonimowej struktury nie będącej jednocześnie definicją
?????; // nie możemy zadeklarować "zapowiadająco"
void foo(?????* p);
typedef struct { // deklaracja będąca definicją
int x;
} A;
Jeżeli piszemy w C++, ale jesteśmy zmuszeni pracować z taką anonimową strukturą z C (legacy...), którą chcielibyśmy zadeklarować "zapowiadająco" - możemy użyć pewnej... No, może "sztuczka" to za dużo powiedziane, ale jest to rozwiązanie, które może nie rzuca się od razu samo na myśl:
//legacy_stuff.h
typedef struct { ... } LegacyType;
//fancy.h
struct fancy_t {
struct LegacyType; // co to za typ?
void foo(LegacyType* p);
};
//fancy.cpp
#include "fancy.h"
extern "C" {
#include "legacy_stuff.h"
}
struct fancy_t::LegacyType : public ::LegacyType { }; // aaa... ;]
//...
Nawet jeżeli mamy alias w C, czy też używamy C++, możemy potrzebować tego struct
jeśli zasłonimy sobie nazwę:
typedef struct A { ... } A; // C
struct A { ... }; // C++
// C / C++
int A; // ...OK! A w tym zakresie odwołuje się teraz do zmiennej
A obj; // FAIL
struct A obj; // OK!