it-swarm.com.de

Was bedeutet void in C, C ++ und C #?

Suchen Sie nach den Grundlagen, woher der Begriff "void" stammt und warum er als void bezeichnet wird. Mit dieser Frage soll jemandem geholfen werden, der keine C-Erfahrung hat und plötzlich eine C-basierte Codebasis sucht.

163
Nick Katsivelos

Grundsätzlich bedeutet es "nichts" oder "kein Typ"

Es gibt drei grundlegende Möglichkeiten, wie Void verwendet wird:

  1. Funktionsargument: int myFunc(void) - Die Funktion benötigt nichts.

  2. Funktionsrückgabewert: void myFunc(int) - die Funktion gibt nichts zurück

  3. Generischer Datenzeiger: void* data - 'data' ist ein Zeiger auf Daten unbekannten Typs und kann nicht dereferenziert werden

Hinweis: Das void in einem Funktionsargument ist in C++ optional, daher ist int myFunc() genau dasselbe wie int myFunc(void) und wird in C # vollständig weggelassen. Es wird immer für einen Rückgabewert benötigt.

217
Gerald

Ich habe es immer als abwesend verstanden. Hier sind vier Fälle in der Sprache C, die zu dieser Verwendung von abwesend passen

  • R f(void) - Funktionsparameter sind abwesend
  • void f(P) - Rückgabewert ist abwesend
  • void *p - Typ dessen, worauf hingewiesen wird, ist abwesend
  • (void) p - Wertverwendung ist abwesend

Andere C-Nachkommen benutzen es für andere Dinge. Die Programmiersprache D verwendet sie für Fälle, in denen ein Initialisierer nicht vorhanden ist

  • T t = void; - Initialisierungswert ist nicht vorhanden

Es gibt zwei Möglichkeiten, um void zu verwenden:

void foo(void);

oder

void *bar(void*);

Der erste gibt an, dass kein Argument übergeben wird oder dass kein Argument zurückgegeben wird.

Der zweite Befehl teilt dem Compiler mit, dass den Daten kein Typ zugeordnet ist. Dies bedeutet, dass Sie die Daten, auf die verwiesen wird, erst verwenden können, wenn sie in einen bekannten Typ umgewandelt wurden.

Zum Beispiel sehen Sie void* wurde häufig verwendet, wenn Sie eine Schnittstelle haben, die eine Funktion aufruft, deren Parameter nicht im Voraus bekannt sind.

Wenn Sie beispielsweise im Linux-Kernel die Arbeit verschieben, richten Sie eine zu einem späteren Zeitpunkt auszuführende Funktion ein, indem Sie ihr einen Zeiger auf die auszuführende Funktion und einen Zeiger auf die Daten geben, die an die Funktion übergeben werden sollen:

struct _deferred_work {
sruct list_head mylist;
.worker_func = bar;
.data        = somedata;
} deferred_work;

Dann geht ein Kernel-Thread eine Liste der zurückgestellten Arbeiten durch und führt, wenn er zu diesem Knoten gelangt, effektiv Folgendes aus:

bar(somedata);

Dann haben Sie in der Bar:

void bar(void* mydata) {
    int *data = mydata;
    /* do something with data */;
}
13

Es bedeutet "kein Wert". Mit void geben Sie an, dass eine Funktion keinen Wert zurückgibt oder keine Parameter oder beides enthält. Ziemlich konsistent mit typischen Verwendungen von Word void in Englisch.

13
sharptooth

Es zeigt das Fehlen eines Rückgabewerts in einer Funktion an.

Einige Sprachen haben zwei Arten von Unterprogrammen: Prozeduren und Funktionen. Prozeduren sind nur eine Folge von Operationen, während eine Funktion eine Folge von Operationen ist, die ein Ergebnis zurückgeben.

In C und seinen Derivaten ist der Unterschied zwischen den beiden nicht explizit. Alles ist im Grunde eine Funktion. Das Schlüsselwort void gibt an, dass es sich nicht um eine "tatsächliche" Funktion handelt, da es keinen Wert zurückgibt.

4
Rik

Stellen Sie sich die Leere als "leere Struktur" vor. Lassen Sie mich erklären.

Jede Funktion benötigt eine Folge von Parametern, wobei jeder Parameter einen Typ hat. Tatsächlich könnten wir die Parameter in eine Struktur packen, wobei die Strukturschlitze den Parametern entsprechen. Damit hat jede Funktion genau ein Argument. In ähnlicher Weise erzeugen Funktionen ein Ergebnis, das einen Typ hat. Es könnte ein Boolescher Wert oder ein Gleitkommawert oder eine Struktur sein, die eine beliebige Menge anderer typisierter Werte enthält. Wenn wir eine Sprache mit mehreren Rückgabewerten wollen, können wir leicht darauf bestehen, dass sie in eine Struktur gepackt werden. Tatsächlich könnten wir immer darauf bestehen, dass eine Funktion eine Struktur zurückgibt. Jetzt nimmt jede Funktion genau ein Argument und erzeugt genau einen Wert.

Was passiert nun, wenn ich eine Funktion benötige, die "no" -Wert erzeugt? Überlegen Sie, was ich bekomme, wenn ich eine Struktur mit 3 Slots bilde: Sie enthält 3 Werte. Wenn ich 2 Steckplätze habe, enthält es zwei Werte. Wenn es einen Slot hat, einen Wert. Und wenn es Null-Slots hat, enthält es ... äh, Null-Werte oder "kein" Wert. Also kann ich mir eine Funktion vorstellen, die void zurückgibt, als würde sie eine Struktur zurückgeben, die keine Werte enthält. Sie können sogar entscheiden, dass "void" ist nur ein Synonym für den Typ, der durch die leere Struktur dargestellt wird, und kein Schlüsselwort in der Sprache (möglicherweise ist es nur ein vordefinierter Typ :)

In ähnlicher Weise kann ich mir eine Funktion vorstellen, die keine Werte erfordert, als eine leere Struktur akzeptierend, z. B. "void".

Auf diese Weise kann ich sogar meine Programmiersprache implementieren. Das Übergeben eines ungültigen Werts nimmt null Byte in Anspruch, sodass das Übergeben von ungültigen Werten nur ein Sonderfall für das Übergeben anderer Werte beliebiger Größe ist. Dies macht es dem Compiler leicht, das Ergebnis oder Argument "void" zu behandeln. Sie möchten wahrscheinlich eine Langauge-Funktion, mit der ein Funktionsergebnis verworfen werden kann. Wenn Sie in C die nicht-leere Ergebnisfunktion foo in der folgenden Anweisung aufrufen: foo (...); Der Compiler weiß, dass foo ein Ergebnis erzeugt und es einfach ignoriert. Wenn void ein Wert ist, funktioniert dies perfekt, und jetzt sind "Prozeduren" (die nur ein Adjektiv für eine Funktion mit ungültigem Ergebnis sind) nur triviale Spezialfälle für allgemeine Funktionen.

Void * ist ein bisschen lustiger. Ich glaube nicht, dass die C-Designer auf diese Weise für ungültig gehalten haben. Sie haben gerade ein Keyword erstellt. Dieses Schlüsselwort war verfügbar, als jemand einen Punkt auf einen beliebigen Typ benötigte, also void * als Redewendung in C. Tatsächlich funktioniert es ziemlich gut, wenn Sie void als leere Struktur interpretieren. Ein void * Zeiger ist die Adresse eines Ortes, an dem diese leere Struktur platziert wurde.

Casts von void * nach T * für andere T-Typen funktionieren ebenfalls mit dieser Perspektive. Pointer Casts sind ein kompletter Cheat, der auf den meisten gängigen Architekturen funktioniert, um die Tatsache auszunutzen, dass bei einem zusammengesetzten Typ T ein Element mit dem Subtyp S physikalisch am Anfang von T in seinem Speicherlayout platziert wird, und dann S * nach T * und Umgekehrt funktioniert es in der Regel, wenn dieselbe physikalische Maschinenadresse verwendet wird, da die meisten Maschinenzeiger eine einzige Darstellung haben. Wenn Sie den Typ S durch den Typ void ersetzen, hat dies genau den gleichen Effekt, und daher funktioniert das Casting in/aus void *.

Die Programmiersprache PARLANSE setzt die obigen Ideen ziemlich genau um. Wir haben das Design vermasselt und "void" als Rückgabetyp nicht besonders beachtet und haben daher langauge Schlüsselwörter für die Prozedur. Es ist meistens nur eine einfache Syntaxänderung, aber eine Sache, an der man nicht vorbeikommt, wenn man einen großen Code in einer Sprache hat.

3
Ira Baxter

In c # würden Sie das Schlüsselwort void verwenden, um anzugeben, dass eine Methode keinen Wert zurückgibt:

public void DoSomeWork()
{
//some work
}
2
Charlie

Wenn Sie das Konzept einem Anfänger erklären, kann es hilfreich sein, eine Analogie zu verwenden. Die Verwendung von void in all diesen Fällen entspricht einer Seite in einem Buch mit den folgenden Worten: "Diese Seite wurde absichtlich leer gelassen." Der Compiler unterscheidet zwischen etwas, das als Fehler gekennzeichnet werden soll, und einem Typ, der absichtlich leer bleiben soll, da dies das gewünschte Verhalten ist.

Es wird immer in Code angezeigt, in dem normalerweise ein Typ angezeigt wird, z. B. ein Rückgabetyp oder ein Zeigertyp. Aus diesem Grund ist void in C # einem tatsächlichen CLR-Typ (System.Void) zugeordnet, da es sich um einen eigenen Typ handelt.

Einige Programmiersprachen haben nie das Konzept der Leere entwickelt, so wie einige menschliche Kulturen das Konzept der Zahl Null nie erfunden haben. Void stellt den gleichen Fortschritt in einer Programmiersprache dar, den das Konzept von Null für die menschliche Sprache darstellt.

2
TimF

Drei Anwendungsfälle für ungültig:

  1. Funktionssignaturen. void foo(int bar) gibt keinen Wert zurück. int bar(void) akzeptiert keine Parameter, dies wird jedoch normalerweise mit einer leeren Argumentliste ausgedrückt: int bar(). Die Verwendung des Schlüsselworts void entspricht hier seiner Bedeutung im Englischen.

  2. Generischer Zeiger vom Typ "top" void *, der auf nicht angegebene Daten verweist und nicht dereferenziert werden kann. Hier unterscheidet sich die Bedeutung von void von anderen Bedeutungen von void: universal type vs. no type.

  3. In Besetzungen wie (void) new Foo(this) um anzuzeigen, dass der Rückgabewert absichtlich weggeworfen wird. Hier stimmt die Keyword-Verwendung auch mit der Bedeutung in Englisch überein.

Die Fälle 1 und 2 wurden bereits von @Gerald behandelt, Fall 3 wurde jedoch noch nicht behandelt.

2
laalto

Es bedeutet "kein Wert". Sie verwenden void, um anzugeben, dass eine Funktion keinen Wert zurückgibt oder keine Parameter oder beides enthält. Dies entspricht weitgehend den typischen Verwendungen von Word void in Englisch.

Void sollte nicht mit null verwechselt werden. Null bedeutet, dass für die Variable, deren Adresse sich auf dem Stapel befindet, der Wert auf dem Heap für diese Adresse leer ist.

1
AVI

Void ist ein unvollständiger Typ, der per Definition kein Wert sein kann. Das bedeutet, dass ihm kein Wert zugewiesen werden kann.

Es kann also auch keinen Wert enthalten.

0
dhein

Void wird nur in Methodensignaturen verwendet. Bei Rückgabetypen bedeutet dies, dass die Methode nichts an den aufrufenden Code zurückgibt. Für Parameter bedeutet dies, dass keine Parameter an die Methode übergeben werden

z.B.

void MethodThatReturnsAndTakesVoid(void)
{
// Method body
}

In C # können wir die Leerstelle für Parameter weglassen und den obigen Code wie folgt schreiben:

void MethodThatReturnsAndTakesVoid()
{
// Method body
}

Void sollte nicht mit null verwechselt werden. Null bedeutet, dass für die Variable, deren Adresse sich auf dem Stapel befindet, der Wert auf dem Heap für diese Adresse leer ist.

0
Rashmi Pandit