Heim  >  Artikel  >  php教程  >  Ausführliche Erklärung von Nichtigkeit und Nichtigkeit*

Ausführliche Erklärung von Nichtigkeit und Nichtigkeit*

高洛峰
高洛峰Original
2016-12-13 13:14:354398Durchsuche

Regeln für die Verwendung des Schlüsselworts void:

1. Wenn die Funktion keinen Rückgabewert hat, sollte sie als void-Typ deklariert werden

2. Wenn die Funktion keine Parameter hat, dann ist sie es Parameter sollten als void deklariert werden;

3. Wenn der Parameter der Funktion ein Zeiger eines beliebigen Typs sein kann, sollte sein Parameter als void * deklariert werden. 4. Void kann nicht dargestellt werden eine echte Variable;

void verkörpert eine Abstraktion. Alle Variablen in dieser Welt sind „typisiert“

################# #### ########################################### ##
1. Übersicht
Viele Anfänger verstehen die Zeigertypen void und void in der Sprache C/C++ nicht und machen daher einige Fehler bei der Verwendung. In diesem Artikel wird die tiefgreifende Bedeutung des Schlüsselworts void erläutert und

die Verwendungsmethoden und -techniken von void und void-Zeigertypen detailliert beschrieben.

2. Die Bedeutung von void
Die wörtliche Bedeutung von void ist „untypisiert“, void * ist ein „untypisierter Zeiger“ und void * kann auf jede Art von Daten verweisen.

void hat fast nur die Funktion, das Programm zu „kommentieren“ und einzuschränken, da noch nie jemand eine void-Variable definiert hat. Versuchen wir, sie zu definieren:


void a;

Diese Anweisungszeile führt beim Kompilieren zu einem Fehler und zur Meldung „illegale Verwendung des Typs ‚void‘“. Selbst wenn void a fehlerfrei kompiliert wird, hat dies jedoch keine praktische Bedeutung.

Die eigentliche Rolle von void ist:
(1) Einschränkung der Funktionsrückgaben;
(2) Einschränkung der Funktionsparameter.

Die beiden oben genannten Punkte werden wir im dritten Abschnitt ausführlich erläutern.

Wie wir alle wissen, können wir Werte zwischen p1 und p2 einander direkt zuweisen, wenn p1 und p2 auf unterschiedliche Datentypen zeigen Es müssen obligatorische Typen verwendet werden.

Der Konvertierungsoperator wandelt den Zeigertyp auf der rechten Seite des Zuweisungsoperators in den Typ des Zeigers auf der linken Seite um.

Zum Beispiel:
float *p1;
int *p2;

Die p1 = p2-Anweisung führt zu einem Kompilierungsfehler, der zur Folge hat: =': kann nicht von 'int *' in 'float *' konvertiert werden", es muss geändert werden in:
p1 = (float *)p2;
void * ist anders, jede Art von Zeiger kann direkt zugewiesen werden dazu ist keine Umwandlung erforderlich:
void *p1;
int *p2;
p1 = p2; Dies bedeutet jedoch nicht, dass void * auch ohne Umwandlung zugewiesen werden kann Andere Arten von Zeigern. Denn „typlos“ kann „typed“ enthalten, „typed“ jedoch nicht

„untyped“. Der Grund ist ganz einfach. Wir können sagen „Männer und Frauen sind Menschen“, aber wir können nicht sagen „Menschen sind Männer“ oder „Menschen sind Frauen“. Die folgende Anweisung kompiliert den Fehler:
void *p1;
int *p2;
p2 = p1;

Eingabeaufforderung „'=': Kann nicht von „void *“ in „int *“ konvertiert werden. '".

3. Verwendung von void

Im Folgenden sind die Regeln für die Verwendung des Schlüsselworts void aufgeführt:
Regel 1 Wenn die Funktion keinen Rückgabewert hat, sollte sie als void-Typ deklariert werden

In der Sprache C wird jede Funktion, die keinen Rückgabewerttyp angibt, vom Compiler so behandelt, als würde sie einen ganzzahligen Wert zurückgeben. Viele Programmierer glauben jedoch fälschlicherweise, dass es sich um einen Void-Typ handelt. Zum Beispiel:
add (int a, int b)
{
return a + b;
}
int main(int argc, char* argv[])
{
printf( "2 + 3 = %d", add ( 2, 3) );
}

Das Ergebnis der Programmausführung ist die Ausgabe:
2 + 3 = 5
Dies zeigt, dass eine Funktion ohne Rückgabewertbeschreibung tatsächlich eine int-Funktion ist.

Dr. Lin Rui erwähnte in „Hochwertige C/C++-Programmierung“: „Die C++-Sprache verfügt über sehr strenge Typsicherheitsprüfungen und lässt nicht zu, dass die obige Situation (bezogen auf Funktionen ohne Typdeklarationen) auftritt. " Der Compiler glaubt dies jedoch nicht unbedingt. In Visual C++ 6.0 wird die obige Add-Funktion beispielsweise ohne Fehler oder Warnungen kompiliert und ordnungsgemäß ausgeführt, sodass wir uns nicht darauf verlassen können, dass der Compiler eine strenge Typprüfung durchführt.

Um Verwirrung zu vermeiden, müssen wir daher beim Schreiben von C/C++-Programmen den Typ jeder Funktion angeben, ohne einen Takt auszulassen. Wenn die Funktion keinen Wert zurückgibt, muss sie als void class

-Typ deklariert werden. Dies ist nicht nur eine Voraussetzung für eine gute Lesbarkeit des Programms, sondern auch eine Voraussetzung für die Standardisierung der Programmierung. Darüber hinaus kann das Hinzufügen der Void-Typ-Deklaration auch die Rolle einer „Selbstanmerkung“ des Codes spielen. Die „Erklärung zur Selbstanmerkung

“ des Codes bedeutet, dass der Code sich selbst mit Anmerkungen versehen kann.

Regel 2: Wenn die Funktion keine Parameter hat, sollten ihre Parameter als void deklariert werden

Eine solche Funktion in der Sprache C++ deklarieren:
int function(void)
{
return 1;
}

Es ist illegal, den folgenden Aufruf durchzuführen:
function(2);

Weil in C++ der Funktionsparameter ungültig ist, was bedeutet Diese Funktion akzeptiert keine Parameter.

Wir kompilieren in Turbo C 2.0:
#include "stdio.h"
fun()
{
return 1;
}
main()
{
printf("%d",fun(2));
getchar();
}

Es wird korrekt kompiliert und gibt 1 aus, was zeigt, dass Sie in der C-Sprache Funktionen ohne Parameter angeben können Die Übergabe von Parametern beliebigen Typs, aber das Kompilieren desselben Codes in einem C++-Compiler führt zu einem Fehler. In C++

können keine Parameter an eine Funktion ohne Parameter übergeben werden und es wird die Fehlermeldung „‚fun‘: Funktion benötigt nicht 1 Parameter“ angezeigt.

Wenn die Funktion daher in C oder C++ keine Parameter akzeptiert, müssen die Parameter als void angegeben werden.

Regel 3: Verwenden Sie den Void-Zeigertyp sorgfältig

Gemäß den ANSI-Standards (American National Standards Institute) können arithmetische Operationen nicht auf Void-Zeigern ausgeführt werden, d. h. die folgenden Operationen sind illegal:
void * pvoid;
pvoid++; //ANSI: Error
pvoid += 1; //ANSI: Error
//Der Grund, warum der ANSI-Standard dies erkennt, besteht darin, dass Zeiger darauf bestehen Algorithmische Operationen müssen sein. Stellen Sie sicher, dass Sie die Größe des Datentyps kennen, auf den sie verweisen.
//Zum Beispiel:
int *pint;
pint++; //ANSI: Richtig

Das Ergebnis von pint++ ist eine Vergrößerung von sizeof(int). (Getestet auf VC6.0, es ist ein Vielfaches von sizeof(int))

Aber das berühmte GNU (Abkürzung für GNU's Not Unix) glaubt nicht daran. Es gibt an, dass die Algorithmusoperation von void * konsistent ist mit char *.

Daher sind die folgenden Anweisungen im GNU-Compiler korrekt:
pvoid++; //GNU: korrekt
pvoid += 1; //GNU: korrekt

Das Ausführungsergebnis von pvoid++ Es wird um 1 erhöht. (Getestet auf VC6.0, es ist ein Vielfaches von sizeof(int))

Um dem ANSI-Standard gerecht zu werden und die Portabilität des Programms zu verbessern, können wir bei der tatsächlichen Programmierung Code schreiben, um das zu erreichen Dieselbe Funktion wie diese:
void * pvoid; //ANSI: korrekt; //ANSI: falsch; richtig

Es gibt einige Unterschiede zwischen GNU und ANSI. Im Allgemeinen ist GNU „offener“ als ANSI und bietet Unterstützung für mehr Syntax. Aber wenn wir tatsächlich entwerfen, sollten wir uns dennoch so weit wie möglich an den

ANSI-Standard halten.

Regel 4 Wenn der Parameter einer Funktion ein Zeiger eines beliebigen Typs sein kann, sollte sein Parameter als void * deklariert werden.

Typische Funktionsprototypen wie die Speicheroperationsfunktionen memcpy und memset sind:
void * memcpy(void *dest, const void *src, size_t len);
void * memset (void * buffer, int c, size_t num);

Auf diese Weise jeder Typ Der Zeiger kann an Memcpy und Memset übergeben werden. Dies spiegelt auch wirklich die Bedeutung der Speicheroperationsfunktion wider, da das von ihr betriebene Objekt nur ein Teil des Speichers ist, unabhängig davon, um welche Art von Speicher es sich handelt. Es wäre wirklich seltsam, wenn der Parametertyp von memcpy und memset nicht void *, sondern char * wäre! Solche Memcpy- und Memset-Funktionen sind offensichtlich keine

„reinen, spaßfreien“ Funktionen!

Der folgende Code wird korrekt ausgeführt:
//Beispiel: memset akzeptiert Zeiger jeden Typs
int intarray[100];
memset ( intarray, 0, 100*sizeof(int) ) ; //Intarray auf 0 löschen

//Beispiel: memcpy akzeptiert Zeiger jeden Typs
int intarray1[100], intarray2[100];
memcpy ( intarray1, intarray2, 100*sizeof( int) ); //Kopiere intarray2 nach intarray1

Interessant ist, dass die Funktionen memcpy und memset auch den Typ void * zurückgeben. Wie gut sich die Autoren der Standardbibliotheksfunktionen auskennen!

Regel 5 void kann keine reale Variable darstellen

Die folgenden Codes versuchen alle, void eine reale Variable darzustellen, daher sind sie alle falsche Codes:
void a; //Fehler
function(void a); //Error

void verkörpert eine Abstraktion. Alle Variablen in dieser Welt sind „typisiert“. Eine Person ist beispielsweise entweder ein Mann oder eine Frau (und eine Transe?). .

Die Entstehung von void dient nur einem abstrakten Bedarf. Wenn Sie das Konzept der „abstrakten Basisklasse“ im objektorientierten Bereich richtig verstehen, ist der void-Datentyp leicht zu verstehen. So wie wir keine Instanz der abstrakten

-Basisklasse definieren können, können wir auch keine void-Variable (nennen wir void analog einen „abstrakten Datentyp“) definieren.

4. Zusammenfassung
Small void enthält eine reichhaltige Designphilosophie. Als Programmierer werden wir sehr davon profitieren, wenn wir auf einer tieferen Ebene über das Problem nachdenken. Unabhängig von der Art des Zeigers (void*, char*, int*, float*...) ist der Standardanfangswert 0xCCCCCCCC//Dies sollte für jeden Compiler unterschiedlich sein, dies gilt für vc6

#include< ; iostream.h>
#include
//#include
void main()
{
void *p1;
int a = 10;
int *p2 = &a;
cout << endl;
cout << (int)*p2 << > p1 = p2;
cout << *(int*)p1 << endl;//!!!!!!
cout << (int)*p2 << endl;
}
/* Ausgabe:
0xCCCCCCCC
10
10
10
* /

wird bei der Deklaration NULL zugewiesen und unmittelbar nach dem Löschen auf NULL gesetzt.


Der Standardanfangswert des Zeigers in der Debug-Version ist 0xCCCCCCCC und der Anfangswert in der Release-Version ist 0x0000000A (VC6.0 auf meinem Computer). Wenn für den Zeiger kein passender Initialisierungswert vorhanden ist, sollte er auf NULL (0) gesetzt werden.
Für gute Programmiergewohnheiten deklarieren Sie einen Zeiger und initialisieren Sie ihn auf NULL. Wenn es sich um ein Klassenmitglied handelt, initialisieren Sie ihn im Konstruktor. Wenn Sie delete für den Zeiger verwenden, setzen Sie ihn auf NULL.


0xCCCCCCCC ist lediglich ein undefinierter Zeigerwert, der von VC im Debug-Status generiert wird, um anzuzeigen, dass dieser Zeiger nicht initialisiert wurde und im Release-Status nicht mit diesem Wert übereinstimmt (es sei denn, es handelt sich um einen Zufall). Wenn für den Zeiger kein passender Initialisierungswert vorhanden ist, sollte er auf NULL (0) gesetzt werden.

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn