Ich schreibe eine Funktion, in der ich 2 type
s Parameter akzeptieren möchte .
- A
string
(char *) - A
structure
wo es n Elemente gibt.
Und um dies zu erreichen, denke ich darüber nach, einen einfachen void *
Parametertyp zu verwenden. Aber ich weiß nicht, wie ich sicher überprüfen soll, ob der Parameter vom einen oder anderen Typ ist.
void*
Punkte zeigen.func_str
undfunc_struct
und Typprüfungen bei der Kompilierung bekommen._Generic
Makro verwenden. Sie können auch selbstidentifizierende Typen erstellen, z. B. mit markierten Gewerkschaften . Dies bedeutet, dass Sie keine rohechar *
Zeichenfolge übergeben können. All das ist wahrscheinlich mehr Ärger als es wert ist.Antworten:
Die Übersetzung von
void*
lautet"Lieber Compiler, dies ist ein Zeiger, und es gibt keine zusätzlichen Informationen für Sie dazu.".
Normalerweise weiß der Compiler es besser als Sie (der Programmierer), aufgrund von Informationen, die er früher erhalten hat und an die er sich noch erinnert und die Sie möglicherweise vergessen haben.
Aber in diesem speziellen Fall wissen Sie es besser oder müssen es besser wissen. In allen Fällen sind
void*
die Informationen ansonsten verfügbar, jedoch nur für den Programmierer, der "zufällig weiß". Der Programmierer muss daher die Informationen dem Compiler - oder besser dem laufenden Programm - zur Verfügung stellen, da der einzige Vorteil darinvoid*
besteht, dass sich die Informationen zur Laufzeit ändern können.Normalerweise erfolgt dies durch Übergabe der Informationen über zusätzliche Parameter an Funktionen, manchmal über den Kontext, dh das Programm "weiß es zufällig" (z. B. gibt es für jeden möglichen Typ eine separate Funktion, je nachdem, welche Funktion aufgerufen wird, impliziert dies den Typ).
Enthält also am Ende
void*
nicht die Typinfo.Viele Programmierer verstehen dies falsch als "Ich muss die Typinformationen nicht kennen".
Das Gegenteil ist der Fall. Die Verwendung von
void*
erhöht die Verantwortung des Programmierers, die Typinformationen zu verfolgen und sie dem Programm / Compiler angemessen zur Verfügung zu stellen.quelle
void*
Funktion springen , in den falschen Typ umwandeln und dann die Daten de-referenzieren ... wird jede Art von undefiniertem Verhalten aufgerufen.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ändlicheenum
zusammen mit dem ziehen müssenvoid*
.Stattdessen sollten Sie C11
_Generic
verwenden, mit dem Typen zur Kompilierungszeit überprüft und die Typensicherheit erhöht werden kann. Beispiel: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:
Wenn Sie so etwas versuchen, erhalten
int x; func(x);
Sie die Compilermeldung"x: incorrect type"
.quelle