Im Englischen wird void als Substantiv definiert als"Leere, Raum, Lücke", und in der Sprache C wird void übersetzt als"kein Typ", entsprechendvoid * ist"typloser Zeiger"。

void scheint nur als "Kommentar" zu dienen und das Programm einzuschränken. Natürlich ist der "Kommentar" hier nicht für uns Menschen gedacht, sondern ein sogenannter Kommentar, der dem Compiler bereitgestellt wird.


Die Rolle von void

1. Einschränken von Funktionsrückgabewerten; dies ist ein häufiger Fall.

2. Einschränken von Funktionsparametern; dies ist ebenfalls recht häufig.

Im Allgemeinen sind dies die beiden Fälle, die wir häufig sehen:

  • Wenn eine Funktion keinen Rückgabewert benötigt, muss void verwendet werden, um sie einzuschränken. Dies ist der erste Fall, den wir erwähnt haben. Zum Beispiel: void func(int a, char *b).
  • Wenn eine Funktion keine Parameter akzeptieren darf, muss void verwendet werden, um sie einzuschränken. Dies ist der zweite Fall, den wir erwähnt haben. Zum Beispiel: int func(void).

Regeln für die Verwendung von void-Zeigern

1. Ein void-Zeiger kann auf Daten jeden Typs zeigen, das heißt, jeder Zeigertyp kann einem void-Zeiger zugewiesen werden. Zum Beispiel:

int *a;
void *p;
p=a;

Wenn Sie den void-Zeiger p einem Zeiger eines anderen Typs zuweisen möchten, benötigen Sie eine Typumwandlung. In diesem Fall:a=(int *)pBei der Speicherzuweisung können wir die Verwendung von void-Zeigern sehen: Der von der Speicherzuweisungsfunktion malloc zurückgegebene Zeiger istvoid *Typ. Wenn dieser Zeiger verwendet wird, muss der Benutzer eine Typumwandlung durchführen, das heißt ausdrücklich angeben, welcher Datentyp in dem Speicher gespeichert ist, auf den der Zeiger zeigt.(int *)malloc(1024)Es bedeutet, ausdrücklich anzugeben, dass in dem Speicher, auf den der von malloc zurückgegebene void*-Zeiger zeigt, int-Daten einzeln gespeichert werden.

2. Im ANSI-C-Standard sind arithmetische Operationen auf void-Zeigern wie p++ oder p+=1 nicht erlaubt, denn da void keinen Typ hat, wissen wir nicht, auf wie vielen Bytes jede arithmetische Operation operieren soll. Beispielsweise arbeitet der Typ char mit sizeof(char) Bytes, während int mit sizeof(int) Bytes operieren muss. In GNU ist es jedoch erlaubt, da GNU standardmäßig annimmt,void *undchar *als identisch ansieht. Da es eindeutig ist, können arithmetische Operationen natürlich durchgeführt werden. Hiersizeof(*p)==sizeof(char)。

void dient fast nur als "Kommentar" und zur Einschränkung des Programms, denn niemand definiert jemals eine void-Variable. Versuchen wir, eine zu definieren:

void a;

Diese Zeile verursacht einen Kompilierungsfehler mit der Meldung"illegal use of type 'void'"Selbst wennvoid abeim Kompilieren keinen Fehler verursacht, hat es keine praktische Bedeutung.

Wie allgemein bekannt ist, können wir, wenn die Zeiger p1 und p2 vom selben Typ sind, direkt zwischen p1 und p2 zuweisen; wenn p1 und p2 auf unterschiedliche Datentypen zeigen, müssen wir den Typumwandlungsoperator verwenden, um den Zeigertyp auf der rechten Seite des Zuweisungsoperators in den Typ des Zeigers auf der linken Seite umzuwandeln.

float *p1;
int *p2;
p1 = p2;
//其中p1 = p2语句会编译出错,
//提示“'=' : cannot convert from 'int *' to 'float *'”,必须改为:
p1 = (float *)p2;

undvoid *Doch void* ist anders; jeder Zeigertyp kann ihm direkt ohne Typumwandlung zugewiesen werden.

void *p1;
int *p2;
p1 = p2;

Aber das bedeutet nicht, dassvoid *auch Zeigern anderer Typen ohne Typumwandlung zugewiesen werden kann. Denn "kein Typ" kann "typisiert" aufnehmen, aber "typisiert" kann "kein Typ" nicht aufnehmen.

Vorsicht bei void-Zeiger-Typen:

Gemäß dem ANSI-Standard (American National Standards Institute) sind arithmetische Operationen auf void-Zeigern nicht erlaubt; das heißt, die folgenden Operationen sind alle unzulässig:

void * pvoid;
pvoid++; //ANSI:错误
pvoid += 1; //ANSI:错误
//ANSI标准之所以这样认定,是因为它坚持:进行算法操作的指针必须是确定知道其指向数据类型大小的。
//例如:
int *pint;
pint++; //ANSI:正确
Das Ergebnis von pint++ ist eine Erhöhung um sizeof(int).

Aber GNU sieht das nicht so; es legt fest, dass die arithmetischen Operationen vonvoid *mit denen vonchar *übereinstimmen. Daher sind die folgenden Anweisungen in GNU-Compilern alle korrekt:

pvoid++; //GNU:正确
pvoid += 1; //GNU:正确

Das Ergebnis der Ausführung von pvoid++ ist, dass es um 1 erhöht wird.

In der tatsächlichen Programmierung können wir, um dem ANSI-Standard zu entsprechen und die Portabilität von Programmen zu verbessern, Code schreiben, der dieselbe Funktionalität wie folgt implementiert:

void * pvoid;
((char *)pvoid)++; //ANSI:错误;GNU:正确
(char *)pvoid += 1; //ANSI:错误;GNU:正确

GNU und ANSI haben auch einige Unterschiede. Insgesamt ist GNU "offener" als ANSI und bietet Unterstützung für mehr Syntax. Aber im praktischen Entwurf sollten wir trotzdem versuchen, uns so weit wie möglich an den ANSI-Standard zu halten. Wenn ein Parameter einer Funktion ein Zeiger beliebigen Typs sein kann, sollte sein Parameter deklariert werden alsvoid *。

Hinweis:Ein void-Zeiger kann auf Daten beliebigen Typs zeigen, was uns in Programmen einige Vorteile bringen kann. Wenn ein Funktionsparameter ein Zeigertyp ist, können wir ihn als void-Zeiger definieren, sodass die Funktion Zeiger beliebigen Typs akzeptieren kann. Zum Beispiel:

Typische Beispiele sind die Funktionsprototypen der Speicheroperationsfunktionen memcpy bzw. memset:

void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );

Auf diese Weise können Zeiger beliebigen Typs an memcpy und memset übergeben werden. Das spiegelt tatsächlich die Bedeutung von Speicheroperationsfunktionen wider, denn das Objekt, auf dem sie operieren, ist nur ein Stück Speicher, unabhängig davon, welchen Typs der Speicher ist (siehe C-Sprachimplementierung generischer Programmierung). Wenn die Parametertypen von memcpy und memset nichtvoid *, sondernchar *wären, wäre das wirklich seltsam! Solche memcpy und memset sind offensichtlich keine „reinen, edlen“ Funktionen! Die Entstehung von void dient nur dem Bedürfnis nach Abstraktion. Wenn man das Konzept der „abstrakten Basisklasse“ in der objektorientierten Programmierung richtig versteht, ist auch der Datentyp void leicht zu verstehen. So wie man keine Instanz einer abstrakten Basisklasse definieren kann, können wir auch keine void-Variable definieren (nennen wir void analog dazu einen „abstrakten Datentyp“).

Original-URL: https://www.cnblogs.com/wuyudong/p/c-void-point.html