void* vs. char* Zeigerarithmetik

Lesezeit: 3 Minuten

Benutzeravatar von de1337ed
de1337ed

Ich blättere in meinem Lehrbuch und bin ein wenig verwirrt über den darin enthaltenen Code. In einem Teil führen sie Zeigerarithmetik auf folgende Weise durch:

void* bp;
...
bp = (void*)((char*)(bp)+16);
...

aber später machen sie Folgendes:

void* bp;
...
bp = bp+16;
...

Ich habe das Gefühl, dass es zwei verschiedene Dinge sein sollten, aber sie behandeln es als dasselbe. Ich denke so, denn wenn Sie beispielsweise auf ein Array zugreifen würden (z. B. auf ein Integer-Array), würden Sie Folgendes tun

int* a = malloc(n*sizeof(int));
...
q = *(a+1);
...

Greife ich in diesem Fall nicht auf die nächsten 4 Bytes im Integer-Array zu und nicht auf das nächste Byte? Ebenso habe ich das Gefühl, dass, wenn ich void* a habe, *(a+1) die nächsten 4 Bytes sein sollten … Oder ist das nicht der Fall? Danke schön.

  • Das zweite Beispiel sollte nicht kompiliert werden.

    – Oliver Charlesworth

    7. April 2012 um 20:48


  • @OliCharlesworth: Es wird nicht kompiliert (oder löst zumindest eine Warnung aus), wenn Sie im konformen Modus kompilieren. gcc ist standardmäßig nicht konform und wird implementiert void* Arithmetik als Erweiterung.

    – Keith Thompson

    7. April 2012 um 20:54

Es ist ein Ausrutscher. Arithmetik weiter void * ist nicht im Standard definiert, aber einige Compiler bieten es als Erweiterung an und verhalten sich genauso wie char * für Arithmetik. Das zweite ist formal kein gültiges C, sondern vermutlich aus (schlechter) Gewohnheit durchgeschlüpft.

  • Der richtige Weg, auf die nächsten 16 Bytes zuzugreifen, wäre also, zuerst in char* umzuwandeln und dann 16 hinzuzufügen? Lol, ich muss jetzt eine ganze Menge Code ändern. Oh, und ich habe das erste etwas falsch abgeschrieben. Ich habe eine kleine Änderung vorgenommen, aber ich glaube nicht, dass es einen Unterschied für meine Frage machen wird.

    – de1337ed

    7. April 2012 um 20:50 Uhr


  • Oder Sie könnten darauf wirken uint64_t * und addiere 2 😉 Ja, die tragbare Möglichkeit besteht darin, einen Zeiger auf einen Typ mit bekannter Größe umzuwandeln und darauf eine Arithmetik durchzuführen. Wenn Sie keine Portabilität benötigen und Ihr Compiler dies dokumentiert void * Arithmetik funktioniert auf eine bestimmte Art und Weise, das können Sie nutzen. Aber natürlich müssen Sie irgendwann auf einen anderen Compiler portieren …

    – Daniel Fischer

    7. April 2012 um 20:53

Benutzeravatar von Antonin GAVREL
Antonin GAVREL

Die akzeptierte Antwort ist eine gute Zusammenfassung und ich möchte klarer machen, warum man die eine oder andere verwendet. 😉

Obwohl (void *) und (char *) gleichermaßen in jeden anderen Zeigertyp umgewandelt werden können, Es ist nur zulässig, eine Zeigerarithmetik mit einem (char *) und nicht mit (void *) durchzuführen, wenn Sie Standard C einhalten möchten.

Warum werden beide als Zeiger verwendet? Die meisten Zeigerkonvertierungen von und nach (void *) können ohne Umwandlung durchgeführt werden, aber die Verwendung von (char *) ist eine Reminiszenz an die alten Zeiten.

GCC warnt nicht vor Zeigerarithmetik bei (void *), da es sich nicht um einen Compiler handelt, der mit Standard C, sondern mit GNU C kompatibel sein soll. Um sich in Übereinstimmung mit Standard C zu verhalten, können Sie die folgenden Flags verwenden:

gcc -ansi -pedantic -Wall -Wextra -Werror <more args...>

Mein Fazit:

  • Falls Sie es wollen Um eine Zeigerarithmetik durchzuführen: verwenden Sie (char *)
  • Falls Sie es wollen um die Zeigeradresse zu erhalten, um sie später in einen anderen Typ umzuwandeln: verwenden Sie (void *)

1453470cookie-checkvoid* vs. char* Zeigerarithmetik

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy