Considérer:
#define MAXROW 20
#define MAXCOL 60
typedef State Grid[MAXROW+2] [MAXCOL+2]
typedef enum state {DEAD,ALIVE} State
Comment utiliser typedef
et typedef enum
en C? Que fait cette partie du code?
typedef enum state {DEAD,ALIVE} State;
| | | | | |^ terminating semicolon, required!
| | | type specifier | | |
| | | | ^^^^^ declarator (simple name)
| | | |
| | ^^^^^^^^^^^^^^^^^^^^^^^
| |
^^^^^^^-- storage class specifier (in this case typedef)
Le mot clé typedef
est un spécificateur de pseudo-classe de stockage. Syntaxiquement, il est utilisé au même endroit où un spécificateur de classe de stockage tel que extern
ou static
est utilisé. Cela n'a rien à voir avec le stockage. Cela signifie que la déclaration n'introduit pas l'existence de objets nommés, mais introduit plutôt des noms qui sont type aliases.
Après la déclaration ci-dessus, l'identifiant State
devient un alias pour le type enum state {DEAD,ALIVE}
. La déclaration fournit également ce type lui-même. Cependant, ce n'est pas typedef
le faire. Toute déclaration dans laquelle enum state {DEAD,ALIVE}
apparaît en tant que spécificateur de type introduit ce type dans la portée:
enum state {DEAD, ALIVE} stateVariable;
Si enum state
a déjà été introduit, la typedef
doit être écrite comme suit:
typedef enum state State;
sinon, la enum
est en cours de redéfinition, ce qui est une erreur.
Comme d’autres déclarations (à l’exception des déclarations de paramètres de fonction), la déclaration typedef
peut avoir plusieurs déclarateurs, séparés par une virgule. De plus, ils peuvent être des déclarants dérivés, pas seulement des noms simples:
typedef unsigned long ulong, *ulongptr;
| | | | | 1 | | 2 |
| | | | | | ^^^^^^^^^--- "pointer to" declarator
| | | | ^^^^^^------------- simple declarator
| | ^^^^^^^^^^^^^-------------------- specifier-qualifier list
^^^^^^^---------------------------------- storage class specifier
Cette typedef
introduit deux noms de type ulong
et ulongptr
, basés sur le type unsigned long
donné dans la liste des qualificateurs de qualificateurs. ulong
est juste un alias direct pour ce type. ulongptr
est déclaré en tant que pointeur sur unsigned long
, grâce à la syntaxe *
, qui, dans ce rôle, est une sorte d'opérateur de construction de type qui imite délibérément le *
unaire pour le déréférencement de pointeur utilisé dans les expressions. En d'autres termes, ulongptr
est un alias du type "pointeur sur unsigned long
".
Alias signifie que ulongptr
n'est pas un type distinct de unsigned long *
. Ce code est valide et ne nécessite aucun diagnostic:
unsigned long *p = 0;
ulongptr q = p;
Les variables q
et p
ont exactement le même type.
L'aliasing de typedef
n'est pas textuel. Par exemple, si user_id_t
est un nom typedef
pour le type int
, nous ne pouvons pas simplement faire ceci:
unsigned user_id_t uid; // error! programmer hoped for "unsigned int uid".
Il s'agit d'une liste de spécificateurs de type non valide, combinant unsigned
avec un nom typedef. Ce qui précède peut être effectué à l'aide du préprocesseur C:
#define user_id_t int
unsigned user_id_t uid;
dans lequel user_id_t
est étendu par macro au jeton int
avant l'analyse syntaxique et la traduction. Bien que cela puisse sembler être un avantage, c'est un faux. éviter cela dans les nouveaux programmes.
Parmi les inconvénients, cela ne fonctionne pas bien pour les types dérivés:
#define silly_macro int *
silly_macro not, what, you, think;
Cette déclaration ne déclare pas what
, you
et think
comme étant du type "pointeur sur int" car la macro-expansion est la suivante:
int * not, what, you, think;
Le spécificateur de type est int
et les déclarateurs sont *not
, what
, you
et think
. Donc, not
a le type de pointeur attendu, mais pas les identificateurs restants.
Et cela représente probablement 99% de tout ce qui concerne typedef
et le type aliasing en C.
typedef
définit un nouveau type de données. Pour que vous puissiez avoir:
typedef char* my_string;
typedef struct{
int member1;
int member2;
} my_struct;
Alors maintenant, vous pouvez déclarer des variables avec ces nouveaux types de données
my_string s;
my_struct x;
s = "welcome";
x.member1 = 10;
Pour enum
, les choses sont un peu différentes - considérons les exemples suivants:
enum Ranks {FIRST, SECOND};
int main()
{
int data = 20;
if (data == FIRST)
{
//do something
}
}
utiliser typedef enum
crée un alias pour un type:
typedef enum Ranks {FIRST, SECOND} Order;
int main()
{
Order data = (Order)20; // Must cast to defined type to prevent error
if (data == FIRST)
{
//do something
}
}
Juste un complément:
6.7.8 Définitions de type
Une déclaration typedef n'introduit pas un nouveau type, mais uniquement un synonyme pour le type ainsi spécifié.
open-std.org ISO/IEC 9899: 2017
Les personnes qui conviennent que typedef
crée un nouveau type de données en C doivent utiliser trow dans la fonction free()
et définir toutes les références à leurs noms sur NULL
.