Est-ce que typedef et #define sont les mêmes en c?

Réponses:

122

Non.

#defineest un jeton de préprocesseur: le compilateur lui-même ne le verra jamais.
typedefest un jeton de compilateur: le préprocesseur ne s'en soucie pas.

Vous pouvez utiliser l'un ou l'autre pour obtenir le même effet, mais il est préférable d'utiliser celui qui convient à vos besoins

#define MY_TYPE int
typedef int My_Type;

Lorsque les choses deviennent "poilues", l'utilisation de l'outil approprié permet de corriger les choses

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

void fx_typ(stdfx fx); /* ok */
void fx_def(FX_TYPE fx); /* error */
pmg
la source
3
Après le typedef stdfx, les objets valides de ce type sont des pointeurs vers des fonctions qui reçoivent un int et ne renvoient pas de valeur.
pmg
1
Pourquoi le #define échouerait-il en cas de pointeur de fonction comme argument?
Allahjane
2
@Allahjane: l'expansion devient void fx_def(void (*)(int) fx);; la déclaration correcte est void fx_def(void (*fx)(int));.
pmg
5
Pointeurs de fonction sont faisables avec des macros, seulement si vous êtes prêt à abandonner la syntaxe: #define FX_TYPE(f) void (*f)(int). Vous déclareriez alors votre fonction comme:void fx_def(FX_TYPE(fx));
plafer
229

typedefobéit aux règles de portée tout comme les variables, alors qu'il definereste valide jusqu'à la fin de l'unité de compilation (ou jusqu'à une correspondance undef).

En outre, certaines choses peuvent être faites avec typedefqui ne peuvent être faites avec define.
Par exemple:

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
la source
23

Non, ils ne sont pas les mêmes. Par exemple:

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

Après le prétraitement, cette ligne se développe en

int* a, b;

J'espère que vous voyez le problème; aaura seulement le type int *; bsera déclaré un plain int(car le *est associé au déclarateur, pas au spécificateur de type).

Comparez cela avec

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

Dans ce cas, les deux aet bauront le type int *.

Il existe des classes entières de typedefs qui ne peuvent pas être émulées avec une macro de préprocesseur, comme des pointeurs vers des fonctions ou des tableaux:

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

Essayez de faire cela avec une macro de préprocesseur.

John Bode
la source
13

#define définit les macros.
typedef définit les types.

Maintenant en disant cela, voici quelques différences:

Avec #define, vous pouvez définir des constantes qui peuvent être utilisées au moment de la compilation. Les constantes peuvent être utilisées avec #ifdef pour vérifier comment le code est compilé et spécialiser certains codes en fonction des paramètres de compilation.
Vous pouvez également utiliser #define pour déclarer des fonctions de macro de recherche et de remplacement miniatures .

typedef peut être utilisé pour donner des alias aux types (ce que vous pourriez probablement faire avec #define également), mais c'est plus sûr en raison de la nature de recherche et de remplacement des constantes #define .
En plus de cela, vous pouvez utiliser la déclaration forward avec typedef qui vous permet de déclarer un type qui sera utilisé, mais qui n'est pas encore lié au fichier dans lequel vous écrivez.

Yochai Timmer
la source
qu'entendez-vous par trouver et remplacer la nature de #define? , Merci
Mohamed El Shenawy
1
Cela signifie qu'avant la compilation, le préprocesseur trouvera toutes les macros et les remplacera par leur syntaxe d'origine
Prince Vijay Pratap
"typedef peut être utilisé pour donner des alias à des types" Cela a expliqué le but pour moi, merci.
Dave Voyles
8

Les macros de préprocesseur (" #define's") sont un outil de remplacement lexical à la "recherche et remplacement". Ils sont totalement indépendants du langage de programmation et ne comprennent pas ce que vous essayez de faire. Vous pouvez les considérer comme un mécanisme de copier / coller glorifié - c'est parfois utile, mais vous devez l'utiliser avec précaution.

Les typedefs sont une fonctionnalité du langage C qui vous permet de créer des alias pour les types. Ceci est extrêmement utile pour rendre les types composés complexes (comme les structures et les pointeurs de fonction) lisibles et manipulables (en C ++, il existe même des situations où vous devez taper un type).

Pour (3): vous devriez toujours préférer les fonctionnalités de langage aux macros de préprocesseur lorsque cela est possible! Utilisez donc toujours des typedefs pour les types et des valeurs constantes pour les constantes. De cette façon, le compilateur peut réellement interagir avec vous de manière significative. N'oubliez pas que le compilateur est votre ami, vous devez donc lui en dire autant que possible. Les macros de préprocesseur font exactement le contraire en cachant votre sémantique au compilateur.

Kerrek SB
la source
Pouvez-vous donner un exemple en C ++ où vous devez taper un type? Je suis juste curieux de savoir.
jyz
@jyzuz: Il y a quelque chose si vous voulez qu'une fonction membre renvoie un tableau de pointeurs de fonction, ou quelque chose comme ça - si vous essayez d'épeler le type, GCC dit en fait "vous devez utiliser un typedef".
Kerrek SB
4

Ils sont très différents, bien qu'ils soient souvent utilisés pour implémenter des types de données personnalisés (c'est ce que je suppose que cette question porte).

Comme pmg l'a mentionné, il #defineest géré par le pré-processeur (comme une opération de copier-coller) avant que le compilateur ne voie le code, et typedefest interprété par le compilateur.

L'une des principales différences (du moins en ce qui concerne la définition des types de données) est qu'elle typedefpermet une vérification de type plus spécifique. Par exemple,

#define defType int
typedef int tdType

defType x;
tdType y;

Ici, le compilateur voit la variable x comme un int, mais la variable y comme un type de données appelé «tdType» qui se trouve être de la même taille qu'un int. Si vous avez écrit une fonction qui a pris un paramètre de type defType, l'appelant pourrait passer un int normal et le compilateur ne connaîtrait pas la différence. Si la fonction prend à la place un paramètre de type tdType, le compilateur s'assurera qu'une variable du type approprié a été utilisée lors des appels de fonction.

En outre, certains débogueurs ont la capacité de gérer typedefs, ce qui peut être beaucoup plus utile que d'avoir tous les types personnalisés répertoriés comme leurs types primitifs sous-jacents (comme ce serait le cas si #definec'était utilisé à la place).

bta
la source
2

Non.
Typedef est un mot-clé C qui crée un alias pour un type.
#define est une instruction pré-processeur, qui crée un événement de remplacement de texte avant la compilation. Lorsque le compilateur accède au code, le mot «#defined» d'origine n'est plus là. #define est principalement utilisé pour les macros et les constantes globales.

Tech Guy itinérant
la source
2
L'usage du terme "pointeur" pourrait ici prêter à confusion.
D'accord. C'est pourquoi je suis retourné et j'ai ajouté un lien vers typdef sur MSDN - juste au cas où quelqu'un à l'avenir utiliserait cette question pour trouver ce qu'est typedef. Mais peut-être que je devrais changer ce mot ...
Travelling Tech Guy
2

AFAIK, non.

typedefvous aide à configurer un «alias» pour un type de données existant. Pour par exemple. typedef char chr;

#defineest une directive de préprocesseur utilisée pour définir des macros ou des substitutions générales de modèles. Pour par exemple. #define MAX 100, remplace toutes les occurrences de MAXpar 100

Chris Tang
la source
0

Comme mentionné ci-dessus, il existe une différence clé entre #defineet typedef. La bonne façon de penser à cela est de voir un typedef comme étant un type "encapsulé" complet. Cela signifie que vous ne pouvez pas y ajouter après l'avoir déclaré.

Vous pouvez étendre un nom de type de macro avec d'autres spécificateurs de type, mais pas un nom de type typedef:

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

typedef int fruit;
unsigned fruit i;   // illegal

De plus, un nom typedef'd fournit le type de chaque déclinateur dans une déclaration.

#define fruit int *
fruit apple, banana;

Après le développement de la macro, la deuxième ligne devient:

int *apple, banana;

Apple est un pointeur vers un int, tandis que banana est un int. En comparaison. un typedef comme celui-ci:

typedef char *fruit;
fruit apple, banana;

déclare que la pomme et la banane sont identiques. Le nom au recto est différent, mais ce sont tous les deux des pointeurs vers un caractère.

Paul
la source
-1

Comme tout le monde l'a dit ci-dessus, ils ne sont pas les mêmes. La plupart des réponses indiquent typedefêtre plus avantageux que #define. Mais permettez-moi de mettre un point positif de #define:
lorsque votre code est extrêmement gros, dispersé dans de nombreux fichiers, il est préférable de l'utiliser #define; cela aide à la lisibilité - vous pouvez simplement prétraiter tout le code pour voir la définition de type réelle d'une variable à l'endroit de sa déclaration elle-même.

abcoep
la source