J'écris une fonction où j'aimerais accepter 2 type
s de paramètres.
- UNE
string
(char *) - UNE
structure
où il y aura n nombre d'éléments.
Et pour y parvenir, je pense utiliser un void *
type de paramètre simple . Mais je ne sais pas comment vérifier si le paramètre est d'un type ou d'un autre, en toute sécurité.
void*
pointe.func_str
etfunc_struct
et obtenir des contrôles de type à la compilation._Generic
macro. Vous pouvez également créer des types auto-identifiables, par exemple avec des unions balisées , ce qui signifie que vous ne pouvez pas transmettre unechar *
chaîne brute . Tout cela est probablement plus difficile que ça en vaut la peine.Réponses:
La traduction de
void*
est"Cher compilateur, ceci est un pointeur, et il n'y a pas d'informations supplémentaires pour vous à ce sujet.".
Habituellement, le compilateur sait mieux que vous (le programmeur), à cause des informations qu'il a obtenues plus tôt et dont il se souvient encore et que vous pourriez avoir oubliées.
Mais dans ce cas particulier, vous savez mieux ou avez besoin de mieux savoir. Dans tous les cas,
void*
les informations sont disponibles autrement, mais uniquement pour le programmeur, qui "arrive à savoir". Le programmeur doit donc fournir les informations au compilateur - ou mieux au programme en cours d'exécution, car le seul avantagevoid*
a est que les informations peuvent changer pendant l'exécution.Habituellement, cela se fait en donnant les informations via des paramètres supplémentaires aux fonctions, parfois via le contexte, c'est-à-dire que le programme "arrive à connaître" (par exemple, pour chaque type possible, il existe une fonction distincte, quelle que soit la fonction appelée, cela implique le type).
Donc, à la fin,
void*
ne contient pas les informations de type.De nombreux programmeurs comprennent mal ceci: "Je n'ai pas besoin de connaître les informations de type".
Mais l'inverse est vrai, l'utilisation de
void*
augmente la responsabilité du programmeur de garder la trace des informations de type et de les fournir de manière appropriée au programme / compilateur.la source
void*
fonction, convertissez le mauvais type, puis dé-référencez les données ... alors toutes sortes de comportements non définis sont invoqués.void*
sont un peu obsolètes pour la programmation générique, il n'y a pas beaucoup de situations où vous devriez les utiliser de nos jours. Ils sont dangereux car ils conduisent à une sécurité de type inexistante. Et comme vous l'avez remarqué, vous perdez également les informations de type, ce qui signifie que vous devrez faire glisser des encombrantsenum
avec levoid*
.Au lieu de cela, vous devez utiliser C11
_Generic
qui peut vérifier les types au moment de la compilation et ajouter une sécurité de type. Exemple:N'oubliez pas de fournir des
const
versions qualifiées ( ) de tous les types que vous souhaitez prendre en charge.Si vous voulez de meilleures erreurs de compilation lorsque l'appelant passe le mauvais type, vous pouvez ajouter une assertion statique:
Si vous essayez quelque chose comme
int x; func(x);
vous obtiendrez le message du compilateur"x: incorrect type"
.la source