Wenn ein Zeiger auf einen bestimmten Typ (sagen wir int
, char
, float
, ..) erhöht wird, wird sein Wert durch die Größe dieses Datentyps erhöht. Wenn ein void
Zeiger, der auf Daten mit einer Größe x
zeigt, inkrementiert wird, wie kann er dann x
Bytes nach vorne zeigen? Woher weiß der Compiler, dass er x
den Wert des Zeigers erhöht?
c
pointers
void-pointers
pointer-arithmetic
Siva Sankaran
quelle
quelle
void
Zeiger, der auf Daten mit einer Größex
zeigt, inkrementiert wird, wie kommt er dann dazu,x
Bytes voraus zu zeigen?" Das tut es nicht. Warum können Leute, die solche Fragen haben, sie nicht testen, bevor sie sie stellen? Weißt du, zumindest auf das Nötigste, wo sie prüfen, ob sie tatsächlich kompiliert werden, was dies nicht tut. -1, kann nicht glauben, dass dies +100 und -0 hat.Antworten:
Endgültige Schlussfolgerung: Arithmetik auf a
void*
ist sowohl in C als auch in C ++ illegal .GCC erlaubt es als Erweiterung, siehe Arithmetik ein
void
- und Funktionszeiger (beachten Sie, dass dieser Abschnitt Teil des Kapitels "C-Erweiterungen" des Handbuchs ist). Clang und ICC erlauben wahrscheinlichvoid*
Arithmetik zum Zwecke der Kompatibilität mit GCC. Andere Compiler (z. B. MSVC) lassen das Rechnen nicht zuvoid*
, und GCC verbietet es, wenn das-pedantic-errors
Flag angegeben ist oder wenn das-Werror-pointer-arith
Flag angegeben ist (dieses Flag ist nützlich, wenn Ihre Codebasis auch mit MSVC kompilieren muss).Der C-Standard spricht
Zitate stammen aus dem Entwurf n1256.
In der Standardbeschreibung der Additionsoperation heißt es:
Die Frage hier ist also, ob
void*
es sich um einen Zeiger auf einen "Objekttyp" handelt oder obvoid
es sich um einen "Objekttyp" handelt. Die Definition für "Objekttyp" lautet:Und der Standard definiert
void
als:Da
void
es sich um einen unvollständigen Typ handelt, handelt es sich nicht um einen Objekttyp. Daher ist es kein gültiger Operand für eine Additionsoperation.Daher können Sie keine Zeigerarithmetik für einen
void
Zeiger ausführen .Anmerkungen
Ursprünglich wurde angenommen, dass
void*
aufgrund dieser Abschnitte des C-Standards Arithmetik zulässig ist:Jedoch,
Das bedeutet also, dass
printf("%s", x)
es die gleiche Bedeutung hat, ob esx
einen Typchar*
oder hatvoid*
, aber es bedeutet nicht, dass Sie mit a rechnen könnenvoid*
.Anmerkung des Herausgebers: Diese Antwort wurde bearbeitet, um die endgültige Schlussfolgerung widerzuspiegeln.
quelle
void*
Zeigerarithmetik nicht erlaubt ist. GCC verfügt über eine Erweiterung , die dies ermöglicht.void*
Arithmetik (zumindest standardmäßig).Zeigerarithmetik ist für
void*
Zeiger nicht zulässig .quelle
void
ist ein unvollständiger Typ , der per Definition niemals vervollständigt werden kann.Wirf es auf einen Zeichenzeiger und erhöhe deinen Zeiger um x Bytes vorwärts.
quelle
char
, Inkrementieren umx
und anschließende Neuinterpretation des neuen Werts als ein anderer Typ ist sowohl sinnloses als auch undefiniertes Verhalten.man 3 qsort
void qsort(void *base, size_t nmemb, size_t size, [snip])
Der C-Standard erlaubt keine Arithmetik mit leeren Zeigern. Allerdings GNU C wird unter Berücksichtigung der Größe der erlaubten nichtig heißt
1
.C11-Standard §6.2.5
Absatz - 19
Das folgende Programm funktioniert im GCC-Compiler einwandfrei.
Möglicherweise erzeugen andere Compiler einen Fehler.
quelle
void *
Genau aus diesem Grund können Sie keine Zeigerarithmetik für Typen durchführen!quelle
Sie müssen es in einen anderen Zeigertyp umwandeln, bevor Sie Zeigerarithmetik ausführen.
quelle
Leere Zeiger können auf einen beliebigen Speicherblock verweisen. Daher weiß der Compiler nicht, wie viele Bytes inkrementiert / dekrementiert werden müssen, wenn eine Zeigerarithmetik für einen ungültigen Zeiger versucht wird. Daher müssen leere Zeiger zuerst auf einen bekannten Typ typisiert werden, bevor sie in eine Zeigerarithmetik einbezogen werden können.
quelle
Der Compiler kennt den Typ Cast. Gegeben a
void *x
:x+1
fügt ein Byte hinzux
, Zeiger geht zu Bytex+1
(int*)x+1
fügtsizeof(int)
Bytes hinzu , Zeiger geht zu Bytex + sizeof(int)
(float*)x+1
Adressbytessizeof(float)
usw.Obwohl das erste Element nicht portierbar ist und gegen das Galateo von C / C ++ verstößt, ist es dennoch C-sprachrichtig, was bedeutet, dass es auf den meisten Compilern zu etwas kompiliert wird, für das möglicherweise ein entsprechendes Flag erforderlich ist (wie -Wpointer-arith).
quelle
Althought the first item is not portable and is against the Galateo of C/C++
Wahr.it is nevertheless C-language-correct
Falsch. Das ist Doppeldenken! Zeigerarithmetikvoid *
ist syntaktisch unzulässig, sollte nicht kompiliert werden und erzeugt in diesem Fall undefiniertes Verhalten. Wenn ein unachtsamer Programmierer das Kompilieren durch Deaktivieren einer Warnung durchführen kann, ist dies keine Entschuldigung.unsigned char*
einensizeof
Wert hinzuzufügen .