struct
et typedef struct
?#define
?struct
et typedef struct
?struct x1 { ... }; typedef struct { ... } x2;
La première écriture déclare un tag de structure
x1
. La deuxième déclare un nouveau type nommé
x2
.
La principale différence est l'utilisation.
La deuxième écriture permet un peu plus l'abstraction de type.
Cela permet de cacher le véritable type derrière x2
,
l'utilisateur n'étant pas sensé savoir que c'est une structure.
struct x1 v1; x2 v2;
Oui.
Voir aussi la question 5.2.
L'une des bonnes façons est d'utiliser des pointeurs sur des
structures qui ne sont pas publiquement définies. On peut en plus
cacher les pointeurs par des typedef
.
Voir aussi la question 5.10.
Oui, c'est parfaitement autorisé. Toutefois, rappelons que les paramètres en C sont passés par valeurs et copiés dans la pile. Pour des grosses structures, il est préférable de passer un pointeur dessus, et éventuellement un pointeur constant.
Il n'existe pas en C d'opérateur ou de fonction pour comparer deux structures. Il faut donc le faire à la main, champs par champs.
Une comparaison bit à bit n'est pas portable, et risque de ne pas marcher, en raison du padding (alignement sur certains octets).
Il faut utiliser les fonctions fread() et fwrite(). Attention : les fichiers obtenus ne sont pas portables.
Une méthode plus portable consiste à enregistrer les structures dans un fichier texte.
La norme prévoit d'initialiser le premier membre d'une union. Pour le reste, ce n'est pas standard. En C99, on peut initialiser les champs d'une union :
union { /* ... */ } u = { .any_member = 42 };
#define
?Il y a peu de différences.
L'un des avantages de l'énumération est que les valeurs numériques sont assignées automatiquement. De plus, une énumération se manipule comme un type de données. Certains programmeurs reprochent aux énumérations de réduire le contrôle qu'ils ont sur la taille des variables de type énumération.
Ceci n'est possible de façon automatique que si les valeurs se suivent.
typedef enum { A, B, C, D} type_e;
Dans cette énumération, les valeurs sont données par le
compilateur dans l'ordre croissant, à partir de 0 et avec un pas de
1. Ainsi, le nombre d'éléments de type_e
est D + 1
.
On peut rajouter un élément à l'énumération qui donne directement le nombre d'éléments :
typedef enum { RED, BLUE, GREEN, YELLOW, NB_COLOR} color_e;
le nombre d'éléments de color_e
est donc NB_COLOR
.
Si l'on est obligé, pour des raisons diverses et variées, de fixer d'autres valeurs aux constantes, alors cette solution ne marche pas. On peut toujours rajouter un champs dans l'énumération et fixer manuellement sa valeur.
On ne peut pas le faire simplement. Il faut écrire une fonction qui le fait. Un problème qui se pose alors est la maintenance, car une modification des valeurs de l'énumération entraîne la nécessité d'une mise à jour de cette fonction.
Voici un code qui limite les problèmes de mise à jour :
/* Fichier foo.itm */ ITEM(FOO_A) ITEM(FOO_B) ITEM(FOO_C) /**/ /* Fichier foo.h */ #ifndef FOO_H #define FOO_H #define ITEM(a) a, typedef enum { #include "foo.itm" FOO_NB } foo_t; #undef ITEM #define ITEM(a) #a, const char * const aFoo[] = { #include "foo.itm" }; #undef ITEM #endif /**/ /* Fichier foo.c */ #include <stdio.h> #include "foo.h" int main(void) { foo_t foo; for (foo = FOO_A; foo < FOO_NB; foo++) { printf("foo=%d ('%s')\n",foo, aFoo[foo]); } return 0; }
Merci à Emmanuel Delahaye pour cet exemple.