2011-02-27 13 views
5

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?

+0

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

+1

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" :-) –

Odpowiedz

7

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).

2

Ponieważ A w typedef może być wieloma symbolami, np. typedef int Integer, *PInteger;. Jest to zgodne ze sposobem definiowania zmiennych (int var, *pvar;).

0

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?

+0

Oczywiście not = D – fouronnes

4

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) .

+0

+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

+0

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

+0

@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. –

2

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.

1

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.

1

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.

Powiązane problemy