Übergeben Void-Typ-parameter in C
Hallo da bin ich an einer Aufgabe arbeiten und in C, wo ich übergeben zu müssen, in einen unbekannten Typ eines Parameters in einer Funktion.
Beispielsweise angenommen ich habe die folgenden:
int changeCount(void* element)
{
element.Count = element.Count++;
return 1;
}
Der Grund, warum variable-element ist ungültig, weil es gibt 3 Arten von Möglichkeiten. Alle 3 aber haben eine member-variable namens "Count".
Wenn ich versuche zu kompilieren, den eigentlichen code, den ich schrieb in Eclipese, bekomme ich die folgende Fehlermeldung:
error: request for member 'Count' in
etwas, was keine Struktur oder union
Ich vermute, dass dies geschieht, weil der compiler nicht wissen, welche Art von "element", bevor die hand. Aber ich verstehe nicht, warum das nicht funktioniert.
Danke für die Hilfe!
- Warum nicht einfach schreiben
element.Count++
anstelle von aufrufen der Funktion? - Nicht direkt relevant für die Frage, aber das Verhalten von
element.Count = element.Count++;
ist nicht definiert. Der Einfachheit halber werde ich-Zustand die Regel wie folgt: Sie können nicht ändern Sie einen Wert, der mehr als einmal im gleichen Ausdruck. Für vollständige details finden Sie unter "6.5 Ausdrücke" in der C-standard.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Müssen Sie die cast der Zeiger auf eine dieser 3 Arten und dann verwenden Sie es. So etwas wie:
Allerdings müssen Sie sicher sein, dass der Typ des Objektes, das Sie casting als casting ein Objekt auf die falsche Art, können gefährlich sein.
*((int *) element)++;
und so weiter.Erste, den Sie übergeben, in einen Zeiger auf void, das ist ein Gültiger Ansatz für die unbekannten Typen, aber Sie müssen auch übergeben Zeiger auf die verschiedenen Objekt-Typen.
C ist nicht eine dynamische Sprache ist also symbolischer Art von Informationen ist weitgehend gelöscht, bevor Sie laufen der Zeit so, wenn Sie sagen, dass Ihr alle drei Arten haben ein Mitglied
Count
dies nicht helfen, mit Ihrer Funktion design.Nur so können Sie den Zugriff
Count
ist durch Gießen Ihrevoid*
parameter den richtigen Typ Zeiger vor derefencing mit->
oder(*element).Count
(d.h. nicht nur.
).Es sei denn, Sie verlassen sich auf Ihre Typen mit einem kompatiblen layout (das ist wahrscheinlich implementierungsabhängig), werden Sie auch brauchen, um passieren etwas, das hilft, Ihre Funktion zu bestimmen, die richtige Besetzung zu führen. An dieser Stelle sollten Sie vielleicht besser mit drei separaten Funktionen und bessere Art Sicherheit.
Sie haben zu werfen es auf die eigentliche Art, aber erhalten Sie möglicherweise unerwartete Ergebnisse in die Strukturen nicht haben, die count-Eigenschaft in der gleichen Stelle.
Denken Sie auch daran, dass, wenn Sie übergeben einen Zeiger auf eine Struktur, die wie folgt aussieht Sie wird, erhöht sich der x-Feld nicht die Anzahl.
Wenn die
.Count
element des gleichen Typs für jede dieser 3 Arten, dann kannst du auch ein makro verwenden. Vorausgesetzt, es ist eine int, die Sie dies tun können:Dies funktionieren wird, weil die
a.Count
- Adresse aufgelöst werden kann, wenn Sie die Funktion aufrufen, nicht nach (wenn Sie nicht wissen, den Typ nicht mehr). Ich gehe davon aus, dass Sie den richtigen Typ aus, wenn Sie die Funktion aufrufen, obwohl. SoSometype x; changeCount(x);
funktioniert, sondern übergeben Sie in etwas, das schon ein(void*)
nicht.Auch Ihrem ursprünglichen Ausdruck
element.Count = element.Count++;
ist eher Bizarr. Wenn Sie erhöhen wollen, verwenden Sieelement.Count++
oderelement.Count = element.Count + 1
.&(a)->Count
korrekt ist -->
hat eine höhere Priorität als&
, also Adresse, die Auflösung ist ok, aber deine version funktioniert nicht korrekt fürchangeCount(some_ptr+4)
einen cast benutzt.
auch Ihr element.Count = element.Count++; Zeile überflüssig ist, Sie brauchen nur zu tun element.count++(das erhöht den Wert um eins)
void*
) ein Objekt ist nicht wahrscheinlich, um zu arbeiten.Beim kompilieren, C verwirft[1] die meisten Typ-Informationen, so dass nur offsets. So, Ihrer Funktion kompilieren, um so etwas wie dieses, in pseudocode:
Den stack_ptr ist die Lage des stack-Frames, die erstellt wurde, wenn Sie anrufen, changeCount, die offset_element ist der Speicherort des Elements argument, relativ zu der stack_ptr, aber was ist offset_Count? Denken Sie daran, alle der compiler kennt dein code ist genau das, was Sie gezeigt haben in Ihrem Beispiel; element ist ein generischer Zeiger, nicht wirklich ein Zeiger auf etwas. Sie sagen dem compiler mit, welche element verweist, durch Gießen oder durch zuweisen an eine variable[2]:
Diese Funktion erzeugt im wesentlichen die gleiche (pseudo -) code wie oben, aber der compiler jetzt weiß, was die offset-Zählung sein sollten.
Du erwähnen, dass es drei Möglichkeiten für die Art von was-element verweist. Es gibt ein paar Möglichkeiten, handling: entweder ein angesehener union oder eines "vererbt" - Struktur. Für eine definierte union verwenden, sagen wir, eine Struktur mit einem element einer Enumeration ermitteln, welche der drei Möglichkeiten und ein anderes element eine union der drei möglichen Strukturen; dies ist ungefähr das, was die ML-Sprachen (OCaml, Haskell, etc.) rufen Sie einen algebraischen Datentyp oder was eine Gewerkschaft ist in Pascal. Für die "Vererbung", könnten Sie Typ-Definitionen:
In diesem Fall könnten Sie die changeCount die oben beschriebene Funktion auf und übergeben Sie einen Zeiger auf eine counted_int_t, counted_double_t, oder counted_charptr_t.
Was passiert, ist, dass der compiler legt die drei Strukturen mit der Anzahl element in der "Nachkomme" Strukturen an der gleichen Stelle solange die counted_t element ist erste. (Zumindest in alle compiler, die ich je benutzt habe, und in jedem bit der code, den ich gesehen habe. Ich denke, das es in der C-standard an einem gewissen Punkt, aber es ist eine ganz normale Redewendung.)
[1] Außer für die debugging-Informationen, wenn Sie gesagt haben, der compiler emittiert es. Ihr Programm keinen Zugriff auf diese Informationen, aber es würde nicht helfen in diesem Fall.
[2] x++ (post-Inkrement) operation inkrementiert die variable (gut, lvalue), dass es angewendet wird; die Abtretung im original-code ist nicht notwendig.
Genau das ist das problem:
Aufrufen einer Methode oder Mitgliedsdaten von Namen ist nicht im Allgemeinen eine Funktion von staticly-typisierte Sprachen.
Sogar ein
void *
können nur zuverlässig casten zu einemT *
, wobei T ein Typ ist, wenn sich der Zeiger ist tatsächlich ein Zeiger auf diesen Typ.In C++ eine Möglichkeit ist es, alle drei Typen Erben von der gleichen virtuellen bass-Klasse X, die hat eine Methode Count (D. H. eine Schnittstelle ICountable). Dann Gießen
X *
und mitp->Count
. Dies wäre die idiomatischen C++ - alle Klassen implementieren das gleiche interface und so waren Sie alle unterstützen diese Methode. Dies würde eine Sprache sein, die unterstützten Verfahren Art der Analog zu den sich auf der gleichen struct-offsets trick gezeigt Tommy McGuire Antwort, das macht die structs alle ähnlichen durch Konvention. Wenn Sie verändern die Strukturen oder die compiler waren ein abweichen von der Norm, die das anordnen von Strukturen, Sie wäre in heißem Wasser.Kann ich nicht helfen, denken, dass dies eher ein Spielzeug ist problematisch, da die Methode so einfach ist, würde man normalerweise nicht wickeln Sie es in eine Funktion - man würde nennen Sie es einfach inline:
T t; t.Count++;
.