Kann ich in C mit void * -Zeigern rechnen?

Lesezeit: 4 Minuten

Benutzeravatar von pm100
pm100

ist das gültig

void *p = &X; /* some thing */
p += 12;

und wenn ja, worauf zeigt p jetzt? Ich habe Code (Drittanbieter), der dies tut (und sauber kompiliert) und ich vermute, dass void * als char * behandelt wurde. Mein treuer K&R schweigt (ish) zu diesem Thema

BEARBEITEN: Meine kleine Test-App läuft gut auf gcc 4.1.1 und behandelt void * als char *. Aber g++ barfs

Ich weiß, wie man es richtig macht. Ich muss wissen, ob ich diese Codebasis bereinigen muss, um alle Stellen zu finden, an denen sie erledigt ist.

BTW gcc -pedantic gibt eine Warnung aus

Zusammenfassung:

Die C-Spezifikation ist mehrdeutig. Es besagt, dass in Bezug auf die Darstellung und Verwendung als Funktionsparameter void* =char*. Aber es schweigt sich über die Zeigerarithmetik aus.

  • gcc (4) erlaubt es und behandelt es als char *
  • g++ lehnt es ab
  • gcc -pedantic warnt davor
  • vs2010 weigert sich sowohl c als auch c++

  • verbunden? stackoverflow.com/questions/1997751/…

    – pmg

    25. Oktober 2010 um 23:54 Uhr

Benutzeravatar von JaredPar
JaredPar

Nein das ist nicht legal. EIN void* kann nicht beliebig erhöht werden. Es muss zuerst in einen bestimmten Typ umgewandelt werden.

Wenn Sie es um eine bestimmte Anzahl von Bytes erhöhen möchten, ist dies die Lösung, die ich verwende.

p = ((char*)p) + 12;

Das char type ist praktisch, da er eine definierte Größe von 1 Byte hat.

BEARBEITEN

Interessant ist, dass es auf gcc mit einer Warnung läuft. Ich habe auf Visual Studio 2010 getestet und festgestellt, dass es nicht kompiliert. Mein begrenztes Verständnis des Standards würde sagen, dass gcc hier der Fehler ist. Können Sie die folgenden Kompilierungsflags hinzufügen

-Wall -ansi -pedantic

  • Visual Studio kompiliert Code standardmäßig als C++, weshalb es einen Fehler auslöst.

    – Casablanca

    25. Oktober 2010 um 23:55 Uhr

  • -pedantic wirft eine Warnung aus. das Kompilieren als c++ fatal es

    – pm100

    25. Oktober 2010 um 23:56 Uhr


  • @casablanca Ich bin immer noch verwirrt darüber, wie inkrementiert wird void* könnte in C überhaupt legal sein. Es scheint sicherlich nicht tragbar zu sein.

    – JaredPar

    25. Oktober 2010 um 23:57 Uhr

  • @JaredPar: Ich bin genauso überrascht wie Sie und warte immer noch auf eine endgültige Antwort darauf.

    – Casablanca

    25. Oktober 2010 um 23:58 Uhr

  • @JaredPar: nein, das glaube ich nicht. Ich habe den Text für den Inkrementoperator nicht wirklich überprüft, aber der Text für den Additionsoperator spricht sicherlich nur von Zeigern auf Objekttypen, während void ist ein unvollständiger Typ. So ((void*)p) + 12; ist ein Verstoß gegen Sprachbeschränkungen (ungültiges Programm). MSVC lehnt es daher zu Recht ab, und GCC gibt ihm zu Recht eine implementierungsdefinierte Semantik und kompiliert es mit einer Warnung.

    – Steve Jessop

    27. Oktober 2010 um 9:53 Uhr


Um aus der Spezifikation zu zitieren:

§6.5.6/2: Für die Addition müssen entweder beide Operanden vom arithmetischen Typ sein, oder ein Operand soll ein Zeiger auf einen Objekttyp sein und der andere vom ganzzahligen Typ. (Inkrementieren entspricht dem Hinzufügen von 1.)

Ein Zeiger auf void ist gemäß diesen Auszügen kein Zeiger auf einen Objekttyp:

§6.2.5/1: […] Typen werden unterteilt in Objekttypen (Typen, die Objekte vollständig beschreiben), Funktionstypen (Typen, die Funktionen beschreiben) und unvollständige Typen (Typen, die Objekte beschreiben, denen jedoch Informationen fehlen, die zum Bestimmen ihrer Größe erforderlich sind).

§6.2.5/19: Der void-Typ besteht aus einer leeren Menge von Werten; es ist ein unvollständiger Typ, der nicht vervollständigt werden kann.

Daher ist Zeigerarithmetik nicht definiert für Zeiger auf void-Typen.

  • +1 für den Hinweis, dass die C-Spezifikation diesbezüglich nicht mehrdeutig ist. Ich möchte hinzufügen, dass dies kein undefiniertes Verhalten ist, da 6.5.6/2 Teil eines Abschnitts “Constraints” ist, sondern dass ein konformer Compiler erforderlich ist, um eine Diagnose (5.1.1.3/1) auszugeben. Im Falle des gcc -pedanticnur eine Warnung, aber dennoch eine Diagnose.

    – Steve Jessop

    26. Oktober 2010 um 2:27 Uhr


Benutzeravatar von ruslik
ruslik

Es hängt vom Compiler ab. Diejenigen, die es zulassen, betrachten sizeof(*(void *)) als 1.

BEARBEITEN: Es ist nur für Void-Zeiger-Arithmetik. Es hätte keinen Sinn, in diesem Fall Schritte von sizeof(int) oder von 0 zu verwenden. Die übliche Erwartung von jemandem, der es verwendet, wäre der kleinstmögliche Schritt.

  • Welcher Compiler ermöglicht das? Das impliziert das sizeof(void) == 1 das ist … nicht gesund.

    – JaredPar

    25. Oktober 2010 um 23:44 Uhr


  • Vielleicht für kleine Werte von 1.

    – Jason Weißhorn

    25. Oktober 2010 um 23:48 Uhr

  • @Jason, danke, dass du ein paar Minuten meines Tages verschwendet hast, als ich hilflos lachend auf meinem Stuhl saß 🙂

    – JaredPar

    25. Oktober 2010 um 23:53 Uhr

  • Für spätere Leser: GCC erwägt sizeof void == 1

    – Phil Müller

    1. Dezember 2017 um 17:30 Uhr


Ihre Vermutung ist richtig.

In der Norm ISO C99, Abschnitt 6.2.5, Absatz 26, wird erklärt, dass Leerzeiger und Zeichenzeiger die gleichen Darstellungs- und Ausrichtungsanforderungen (Paraphrasierung) haben.

Benutzeravatar von VikramW
VikramW

Vielleicht möchten Sie sich die am häufigsten gewählte Antwort auf diese Frage ansehen

Zeigerarithmetik für Void-Zeiger in C

Benutzeravatar von alex
Alex

Ich glaube nicht, dass Sie das können, weil es seinen Typ nicht kennt und daher nicht nach der richtigen Anzahl von Bytes suchen kann.

Cast es zuerst in einen Typ, dh (int).

1432830cookie-checkKann ich in C mit void * -Zeigern rechnen?

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

Privacy policy