Ist dieser Hack standardgemäß gültig?

8

Das ist genau wie struct hack. Ist es nach Norm C gültig?

%Vor%     
Nyan 25.07.2010, 14:45
quelle

6 Antworten

6

Ja, es ist absolut gültig. Und das würde ich dringend empfehlen, wenn Sie unnötige zusätzliche Zuweisungen vermeiden (und die Fehlerbehandlung und Speicherfragmentierung vermeiden). Andere können unterschiedliche Meinungen haben.

Übrigens, wenn Ihre Daten nicht void * sind, sondern etwas, auf das Sie direkt zugreifen können, ist es noch einfacher (und effizienter, weil es Platz spart und die zusätzliche Indirektion vermeidet), um Ihre Struktur wie folgt zu deklarieren:

%Vor%

und reservieren Sie Speicherplatz für die benötigte Datenmenge. Die [] -Syntax ist nur in C99 gültig, daher sollten Sie für C89-Kompatibilität stattdessen [1] verwenden, was jedoch einige Bytes verschwenden könnte.

    
R.. 25.07.2010, 14:52
quelle
4

Die Zeile, die Sie in Frage stellen, ist gültig - wie andere bereits gesagt haben.

Interessanterweise ist die nächste Zeile, die Sie nicht abgefragt haben, syntaktisch gültig, gibt Ihnen aber nicht die gewünschte Antwort (außer im Fall num == 0 ).

%Vor%

Der Wert von f + 1 ist ein foo * (implizit durch die Zuweisung in ein void * umgewandelt).

Der Wert von f + 1 + num ist auch ein foo * ; Es zeigt auf die num+1 th foo .

Was Sie wahrscheinlich im Sinn hatten, war:

%Vor%

Oder:

%Vor%

Beachten Sie, dass GCC zwar erlaubt, num zu einem void-Zeiger hinzuzufügen, und es behandelt, als ob sizeof(void) == 1 , der C-Standard gibt Ihnen diese Erlaubnis nicht.

    
Jonathan Leffler 25.07.2010 15:56
quelle
1

Das ist ein altes Spiel, obwohl die übliche Form wie

ist %Vor%

und ordnen Sie dann den Speicherplatz so groß wie Sie möchten und verwenden Array als ob es die gewünschte Größe hatte.

Es ist gültig, aber ich würde Sie ermutigen, wenn möglich einen anderen Weg zu finden: Es gibt viele Möglichkeiten, dies zu vermasseln.

    
dmckee 25.07.2010 14:52
quelle
1

Ja, die allgemeine Idee des Hacks ist gültig, aber zumindest habe ich sie nicht richtig implementiert. So viel hast du richtig gemacht:

%Vor%

Aber das ist falsch:

%Vor%

Da f ist foo * , wird f+1+num in sizeof(foo) berechnet - dh es entspricht f[1+num] - es versucht (versucht) auf die 1+num th foo in einem Array. Ich bin mir ziemlich sicher, das ist nicht was du willst. Wenn Sie die Daten zuweisen, übergeben Sie sizeof(foo)+num+MAX_COMMENT_SIZE , also wofür Sie Platz reservieren, ist num char s, und was Sie (vermutlich) wollen, ist f->comment auf eine Stelle im Speicher zu zeigen, die num char ist s nach f->data , was mehr wie folgt aussehen würde:

%Vor%

Durch das Umwandeln von f in char * wird die Berechnung in char s anstelle von foo s durchgeführt.

OTOH, da Sie immer MAX_COMMENT_SIZE für comment zuweisen, würde ich wahrscheinlich die Dinge (ziemlich) etwas vereinfachen und etwas wie folgt verwenden:

%Vor%

Und dann weise es zu:

%Vor%

und es funktioniert ohne Zeigerbearbeitung überhaupt. Wenn Sie einen C99-Compiler haben, können Sie dies leicht ändern:

%Vor%

und zuteilen:

%Vor%

Das hat den zusätzlichen Vorteil, dass der Standard es tatsächlich segnet, obwohl in diesem Fall der Vorteil ziemlich gering ist (ich glaube die Version mit data[1] wird mit jedem existierenden C89 / 90 Compiler funktionieren).

    
Jerry Coffin 25.07.2010 15:53
quelle
0

Ein anderes mögliches Problem könnte die Ausrichtung sein.

Wenn Sie einfach Ihre f->data malloc, dann können Sie sicher z. Konvertiere dein void* in double* und benutze es um ein double zu lesen / schreiben (vorausgesetzt, dass num ausreichend groß ist). In Ihrem Beispiel können Sie dies jedoch nicht mehr tun, da die f- & gt; -Daten möglicherweise nicht richtig ausgerichtet sind. Um zum Beispiel doppelte Daten in f- & gt; -Daten zu speichern, müssen Sie etwas wie memcpy anstelle einer einfachen Typumwandlung verwenden.

    
Jukka Suomela 25.07.2010 16:47
quelle
0

Ich würde lieber eine Funktion verwenden, um die Daten dynamisch zuzuweisen und sie stattdessen korrekt freizugeben.

Die Verwendung dieses Tricks erspart Ihnen nur die Mühe, die Datenstruktur zu initialisieren und kann zu sehr schlechten Problemen führen (siehe Jerrys Kommentar).

Ich würde so etwas tun:

%Vor%

Beachten Sie, dass ich die Gültigkeit der Daten nicht überprüft habe, und meine Zuweisung kann optimiert werden (Ersetzen von Strlen () -Aufrufen durch einen gespeicherten Längenwert).

Es scheint mir, dass dieses Verhalten sicherer ist ... zum Preis eines verbreiteten Datenblocks vielleicht.

    
Gui13 27.07.2010 10:13
quelle

Tags und Links