Sind typedef und #define in c gleich?

Antworten:

122

Nein.

#defineist ein Präprozessor-Token: Der Compiler selbst wird es nie sehen.
typedefist ein Compiler-Token: Der Präprozessor kümmert sich nicht darum.

Sie können den einen oder anderen verwenden, um den gleichen Effekt zu erzielen, aber es ist besser, den richtigen für Ihre Bedürfnisse zu verwenden

#define MY_TYPE int
typedef int My_Type;

Wenn die Dinge "haarig" werden, macht es die Verwendung des richtigen Werkzeugs richtig

#define FX_TYPE void (*)(int)
typedef void (*stdfx)(int);

void fx_typ(stdfx fx); /* ok */
void fx_def(FX_TYPE fx); /* error */
pmg
quelle
3
Nach dem typedef stdfxsind gültige Objekte dieses Typs Zeiger auf Funktionen, die ein int empfangen und keinen Wert zurückgeben.
PMG
1
Warum sollte die #define im Fall des Funktionszeigers als Argument fehlschlagen?
Allahjane
2
@ Allahjane: Die Erweiterung wird void fx_def(void (*)(int) fx);; Die richtige Erklärung lautet void fx_def(void (*fx)(int));.
PMG
5
Funktionszeiger sind mit Makros nur möglich, wenn Sie bereit sind, die Syntax aufzugeben : #define FX_TYPE(f) void (*f)(int). Sie würden dann Ihre Funktion deklarieren als:void fx_def(FX_TYPE(fx));
Plafer
229

typedefBefolgen Sie die defineGültigkeitsregeln genau wie Variablen, während sie bis zum Ende der Kompilierungseinheit (oder bis zu einem Abgleich undef) gültig bleiben .

Es können auch einige Dinge erledigt werden, mit typedefdenen nicht gearbeitet werden kann define.
Beispielsweise:

typedef int* int_p1;
int_p1 a, b, c;  // a, b, c are all int pointers

#define int_p2 int*
int_p2 a, b, c;  // only the first is a pointer, because int_p2
                 // is replaced with int*, producing: int* a, b, c
                 // which should be read as: int *a, b, c
typedef int a10[10];
a10 a, b, c;  // create three 10-int arrays
typedef int (*func_p) (int);
func_p fp;  // func_p is a pointer to a function that
            // takes an int and returns an int
Andreas Grech
quelle
23

Nein, sie sind nicht gleich. Beispielsweise:

#define INTPTR int*
...
INTPTR a, b;

Nach der Vorverarbeitung wird diese Zeile auf erweitert

int* a, b;

Hoffentlich sehen Sie das Problem; nur awird den Typ haben int *; bwird als normal deklariert int(da das *dem Deklarator zugeordnet ist, nicht dem Typbezeichner).

Vergleichen Sie das mit

typedef int *INTPTR;
...
INTPTR a, b;

In diesem Fall haben beide aund bTyp int *.

Es gibt ganze Klassen von Typedefs, die mit einem Präprozessor-Makro nicht emuliert werden können, z. B. Zeiger auf Funktionen oder Arrays:

typedef int (*CALLBACK)(void);
typedef int *(*(*OBNOXIOUSFUNC)(void))[20]; 
...
CALLBACK aCallbackFunc;        // aCallbackFunc is a pointer to a function 
                               // returning int
OBNOXIOUSFUNC anObnoxiousFunc; // anObnoxiousFunc is a pointer to a function
                               // returning a pointer to a 20-element array
                               // of pointers to int

Versuchen Sie dies mit einem Präprozessor-Makro.

John Bode
quelle
13

#define definiert Makros.
typedef definiert Typen.

Nun sagen wir das, hier sind ein paar Unterschiede:

Mit #define können Sie Konstanten definieren, die in der Kompilierungszeit verwendet werden können. Die Konstanten können mit #ifdef verwendet werden , um zu überprüfen, wie der Code kompiliert wird, und um bestimmten Code gemäß den Kompilierungsparametern zu spezialisieren.
Sie können auch verwenden #define Miniatur Suchen und ersetzen zu erklären Makro - Funktionen .

typedef kann verwendet werden , Aliase Typen zu geben (die Sie wahrscheinlich mit tun könnten #define auch), aber es ist sicherer , weil die Fund-und-Ersetzen - Natur von #define Konstanten.
Außerdem können Sie die Vorwärtsdeklaration mit typedef verwenden , mit der Sie einen Typ deklarieren können, der verwendet wird, aber noch nicht mit der Datei verknüpft ist, in die Sie schreiben.

Yochai Timmer
quelle
Was meinst du mit Finden und Ersetzen der Natur von #define? , Danke
Mohamed El Shenawy
1
Dies bedeutet, dass der Präprozessor vor dem Kompilieren alle Makros findet und sie durch ihre ursprüngliche Syntax ersetzt
Prince Vijay Pratap
"typedef kann verwendet werden, um Typen Aliase zu geben" Dies erklärte den Zweck für mich, danke.
Dave Voyles
8

Präprozessor-Makros (" #define's") sind ein lexikalisches Ersatzwerkzeug a la "Suchen und Ersetzen". Sie sind völlig unabhängig von der Programmiersprache und haben kein Verständnis dafür, was Sie versuchen zu tun. Sie können sich diese als verherrlichte Kopier- / Einfügemechanik vorstellen - gelegentlich ist das nützlich, aber Sie sollten sie mit Vorsicht verwenden.

Typedefs sind eine C-Sprachfunktion, mit der Sie Aliase für Typen erstellen können. Dies ist äußerst nützlich, um komplizierte zusammengesetzte Typen (wie Strukturen und Funktionszeiger) lesbar und handhabbar zu machen (in C ++ gibt es sogar Situationen, in denen Sie einen Typ eingeben müssen ).

Für (3): Sie sollten immer Sprachfunktionen Präprozessormakros vorziehen, wenn dies möglich ist! Verwenden Sie daher immer typedefs für Typen und konstante Werte für Konstanten. Auf diese Weise kann der Compiler tatsächlich sinnvoll mit Ihnen interagieren. Denken Sie daran, dass der Compiler Ihr Freund ist, also sollten Sie ihm so viel wie möglich erzählen. Präprozessor-Makros machen genau das Gegenteil, indem sie Ihre Semantik vor dem Compiler verbergen .

Kerrek SB
quelle
Können Sie ein Beispiel in C ++ nennen, in dem Sie einen Typ eingeben müssen? Ich bin nur neugierig darauf.
JYZ
@jyzuz: Es gibt etwas, wenn eine Member-Funktion ein Array von Funktionszeigern zurückgeben soll, oder so etwas - wenn Sie versuchen, den Typ zu buchstabieren, sagt GCC tatsächlich "Sie müssen ein typedef verwenden".
Kerrek SB
4

Sie sind sehr unterschiedlich, obwohl sie häufig zur Implementierung benutzerdefinierter Datentypen verwendet werden (worum es bei dieser Frage vermutlich geht).

Wie bereits erwähnt, #definewird pmg vom Vorprozessor (wie beim Ausschneiden und Einfügen) behandelt, bevor der Compiler den Code sieht, und typedefvom Compiler interpretiert.

Einer der Hauptunterschiede (zumindest bei der Definition von Datentypen) besteht darin, dass typedefeine spezifischere Typprüfung möglich ist. Beispielsweise,

#define defType int
typedef int tdType

defType x;
tdType y;

Hier sieht der Compiler die Variable x als int, aber die Variable y als Datentyp namens 'tdType', der zufällig dieselbe Größe wie ein int hat. Wenn Sie eine Funktion geschrieben haben, die einen Parameter vom Typ defType verwendet, könnte der Aufrufer ein normales int übergeben, und der Compiler würde den Unterschied nicht kennen. Wenn die Funktion stattdessen einen Parameter vom Typ tdType verwenden würde, würde der Compiler sicherstellen, dass bei Funktionsaufrufen eine Variable des richtigen Typs verwendet wird.

Einige Debugger können auch mit typedefs umgehen , was viel nützlicher sein kann, als alle benutzerdefinierten Typen als zugrunde liegende primitive Typen aufzulisten (wie es der Fall wäre, wenn #definesie stattdessen verwendet würden).

bta
quelle
2

No.
typedef ist ein C Schlüsselwort , das einen Alias für einen Typ erzeugt.
#define ist eine Vorprozessoranweisung, die vor dem Kompilieren ein Textersetzungsereignis erstellt. Wenn der Compiler zum Code gelangt, ist das ursprüngliche Wort "#defined" nicht mehr vorhanden. #define wird hauptsächlich für Makros und globale Konstanten verwendet.

Travelling Tech Guy
quelle
2
Die Verwendung des Begriffs "Zeiger" könnte hier zu Verwirrung führen.
Einverstanden. Deshalb bin ich zurückgegangen und habe einen Link zu typdef auf MSDN hinzugefügt - nur für den Fall, dass jemand in Zukunft diese Frage verwenden wird, um herauszufinden, was typedef ist. Aber vielleicht sollte ich dieses Wort ändern ...
Travelling Tech Guy
2

AFAIK, Nr.

typedefhilft Ihnen beim Einrichten eines "Alias" für einen vorhandenen Datentyp. Zum Beispiel. typedef char chr;;

#defineist eine Präprozessor- Direktive, die zum Definieren von Makros oder allgemeinen Mustersubstitutionen verwendet wird. Zum Beispiel. #define MAX 100, ersetzt alle Vorkommen von MAXmit 100

Chris Tang
quelle
0

Wie oben erwähnt, gibt es einen wesentlichen Unterschied zwischen #defineund typedef. Der richtige Weg, darüber nachzudenken, besteht darin, ein typedef als einen vollständigen "gekapselten" Typ anzusehen. Dies bedeutet, dass Sie es nicht hinzufügen können, nachdem Sie es deklariert haben.

Sie können einen Makrotypnamen mit anderen Typspezifizierern erweitern, jedoch nicht mit einem typedefd Typnamen:

#define fruit int
unsigned fruit i;   // works fine

typedef int fruit;
unsigned fruit i;   // illegal

Außerdem gibt ein typedef'd-Name den Typ für jeden Deklarator in einer Deklaration an.

#define fruit int *
fruit apple, banana;

Nach der Makroerweiterung wird die zweite Zeile:

int *apple, banana;

Apple ist ein Zeiger auf ein Int, während Banane ein Int ist. Im Vergleich. ein typedef wie folgt:

typedef char *fruit;
fruit apple, banana;

erklärt, dass sowohl Apfel als auch Banane gleich sind. Der Name auf der Vorderseite ist unterschiedlich, aber beide sind Zeiger auf ein Zeichen.

paul
quelle
-1

Wie alle oben sagten, sind sie nicht gleich. Die meisten Antworten typedefsind vorteilhafter als #define. Aber lassen Sie mich einen Pluspunkt setzen #define:
Wenn Ihr Code extrem groß ist und über viele Dateien verteilt ist, ist es besser, ihn zu verwenden #define. Es hilft bei der Lesbarkeit - Sie können einfach den gesamten Code vorverarbeiten, um die tatsächliche Typdefinition einer Variablen an der Stelle ihrer Deklaration selbst anzuzeigen.

abcoep
quelle