Poniżej określone A
być zastąpiony przez B
:Dlaczego argumenty #define i typedef są odwrócone?
#define A B
niniejsza określa A
być aliasem dla typuB
:
typedef B A;
Dlaczego? Czy to nie jest niespójne?
Poniżej określone A
być zastąpiony przez B
:Dlaczego argumenty #define i typedef są odwrócone?
#define A B
niniejsza określa A
być aliasem dla typuB
:
typedef B A;
Dlaczego? Czy to nie jest niespójne?
Upraszczając: rozważyć następujące deklaracje zmiennych:
// declare a variable called "myInt" with type int
int myInt;
// declare a variable called "myDouble" with type double
double myDouble;
// declare a variable called "myLong" with type long
long myLong;
// declare a variable called "myFunc" with type pointer to function
void (*myFunc)(char*);
Następnie typedef
s uczynić sens:
// declare a type alias called "myInt" with type int
typedef int myInt;
// declare a type alias called "myDouble" with type double
typedef double myDouble;
// declare a type alias called "myLong" with type long
typedef long myLong;
// declare a type alias called "myFunc" with type pointer to function
typedef void (*myFunc)(char*);
Makra, z drugiej strony, może podjąć się składnią funkcji stylu :
#define A(B, C) B, C
A(1, 2) // expands out to 1, 2
Tak więc w przypadku makr "definicja" pojawia się po nazwie "mak" więcej sensu.
(Odnosi się do C++ też, nawiasem mówiąc).
Ponieważ A
w typedef
może być wieloma symbolami, np. typedef int Integer, *PInteger;
. Jest to zgodne ze sposobem definiowania zmiennych (int var, *pvar;
).
Tak, składnia typedef ma tendencję do wyrzucania mnie trochę. Zakładam, że twoje pytanie to więcej skargi - C ma prawie 40 lat, nie oczekujesz zmiany składni typedef, prawda?
Oczywiście not = D – fouronnes
Tak, makra są bardzo bałagan.
typedef
został dodany do języka dość długo po zakończeniu większości pozostałych języków. Używa tej samej składni jako klasa przechowywania:
static int x;
extern int y;
typedef int z;
Określają one x
, y
i z
jak wszystko jest int
- różnica jest taka, że x
i y
są obiektami typu int
i z
jest w zasadzie aliasem int
sam.
Jako taki, typedef
pasuje do języka w miarę dobrze, i to (jak zwykle) preprocesor to naprawdę "dziwny człowiek na zewnątrz". W tym samym czasie możesz twierdzić, że reszta języka również powinna się zmienić. Tuż za oczywisty przykład Pascal grubsza odwrócony porządek rzeczy:
type
z = integer;
var
x : integer;
Choć nie zrobić dużo różnicy dla trywialnych przykładów, myślę, że jest to raczej prostsze do odczytania, zwłaszcza gdy mamy do czynienia z bardziej złożone deklaracje. Na dobre czy na złe jednak Pascal (w większości) wypadł z łask, a nowsze języki, takie jak Java, zachowały tę szczególną część składni C (tj. Część C, którą zachowywali, była jedyną rzeczą, która najbardziej wymaga zmiany) .
+1: Dobrze zapamiętać pojęcie słowa kluczowego do deklarowania deklaracji. Zawsze, zawsze zastanów się dwa razy zanim wprowadzisz konstrukcję języka przywoływaną przez samą kolejność składni, bez słowa kluczowego/operatora. – Potatoswatter
Dlaczego mówisz, że makra (co sugeruje pre-procesor C) to bałagan? Czy jest to coś zupełnie innego w porównaniu z językiem C? Absolutnie (np. Późne wiązanie w porównaniu do wczesnego wiązania). Czy trudno jest w pełni się nauczyć? Tak, może. Ale czy to bałagan? Nie to, co widzę. Czy mógłbyś wyjaśnić, co masz na myśli mówiąc "bałagan"? – hlovdal
@hlovdal: Kilka najbardziej oczywistych problemów to: 1) brak zakresu, 2) informacje niedostępne dla debuggerów, 3) bardzo podatne na błędy (np. Wielokrotnie analizowane argumenty). Są * rzadko * najlepszym dostępnym rozwiązaniem. –
typedef jest z punktu widzenia składni język w grupie storage class specifier
wraz z extern
i static
(*), a tym samym typedef ma takie samo jak rozmieszczenie tych. To oczywiście nie należy do tej grupy, ale myślę, że prawdopodobnie było tam, gdzie było najmniej źle umieszczone.
(*) Klasa przechowywania obejmuje także auto
i register
, ale nikt już ich nie używa.
Nie wiem, dlaczego w odniesieniu do decyzji językowych, ale sposób, w jaki typedef ma sens.
Specyfikator typedef
jest częścią języka. Służy jako alias do nazwy. Zawsze możesz wpisać, jaki typ znajduje się w deklaracji zmiennej.
struct arr { int len; char *chars; } name;
struct arr another_name;
Korzystanie typedef
lustra tego zastosowania z wyjątkiem zamiast deklarowania zmiennej typu, jesteś deklarowania nazwę typu.
typedef struct { int len; char *chars; } arr;
arr name;
arr another_name;
Dyrektywa #define
jest częścią preprocesora, a nie języka, tak że nie jest związana ze sposobem język reprezentuje pewne konstrukty i może korzystać z bardziej naturalny sposób deklarowania go.
Ponieważ preprocesor i kompilator to w rzeczywistości dwa różne programy, każdy z własną składnią. Można połączyć preprocesor z innymi językami bez większych trudności (robiłem to w dawnych czasach przy użyciu cpp
w programach dBase III i AutoLISP, ponieważ w tych językach brakowało dobrego mechanizmu włączania stałych). Jak już inni już zauważyli, typedef
postępuje zgodnie ze składnią systemu deklaracji C i #define
jest prostą deklaracją zamiany.
PS: Wiem, że są całkowicie różne i używane do bardzo różnych celów. Ale osobiście uważam, że typedef powinien być odwrotnie. – fouronnes
Jeśli to jakieś pocieszenie, Ken Thompson myśli tak samo. W Go, chociaż nie ma bezpośredniego odpowiednika "typedef", który tworzy tylko alias typu, sposobem na stworzenie nowego typu ze starego jest 'type NewType OldType'. Zastanawiam się, czy on i Dennis Ritchie będą argumentować bezpośrednie decyzje dotyczące składni, które Go jednoznacznie doprowadza do podobnej do różnej wartości C. Deklaracja w Go jest zasadniczo "odwrotnie" :-) –