void*
sind für die generische Programmierung etwas veraltet, es gibt nicht viele Situationen, in denen Sie sie heutzutage verwenden sollten. Sie sind gefährlich, weil sie zu nicht vorhandener Sicherheit führen. Und wie Sie bemerkt haben, verlieren Sie auch die Typinformationen, was bedeutet, dass Sie einige umständliche enum
zusammen mit dem ziehen müssen void*
.
Stattdessen sollten Sie C11 _Generic
verwenden, mit dem Typen zur Kompilierungszeit überprüft und die Typensicherheit erhöht werden kann. Beispiel:
#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);
}
Denken Sie daran, qualifizierte ( const
) Versionen aller Typen bereitzustellen, die Sie unterstützen möchten.
Wenn Sie bessere Compilerfehler wünschen, wenn der Aufrufer den falschen Typ übergibt, können Sie eine statische Zusicherung hinzufügen:
#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)
Wenn Sie so etwas versuchen, erhalten int x; func(x);
Sie die Compilermeldung "x: incorrect type"
.
void*
Punkte zeigen.