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 encombrants enum
avec le void*
.
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:
#include <stdio.h>
typedef struct
{
int n;
} s_t; // some struct
void func_str (const char* str)
{
printf("Doing string stuff: %s\n", str);
}
void func_s (const s_t* s)
{
printf("Doing struct stuff: %d\n", s->n);
}
#define func(x) _Generic((x), \
char*: func_str, const char*: func_str, \
s_t*: func_s, const s_t*: func_s)(x) \
int main()
{
char str[] = "I'm a string";
s_t s = { .n = 123 };
func(str);
func(&s);
}
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:
#define type_check(x) _Static_assert(_Generic((x), \
char*: 1, const char*: 1, \
s_t*: 1, const s_t*: 1, \
default: 0), #x": incorrect type.")
#define func(x) do{ type_check(x); _Generic((x), \
char*: func_str, const char*: func_str, \
s_t*: func_s, const s_t*: func_s)(x); }while(0)
Si vous essayez quelque chose comme int x; func(x);
vous obtiendrez le message du compilateur "x: incorrect type"
.
void*
pointe.