Ist dieser Code korrekt??
-
Danke werd ich so machen

Michael E. schrieb:
Edit: Ach ja, sizeof(char) ist immer 1.
Ich weiß, aber ich hab das ganze mit anderen Typen und einfach schnell kopiert und den Typ geändert

-
ICH000 schrieb:
Ich weiß, aber ich hab das ganze mit anderen Typen und einfach schnell kopiert und den Typ geändert

Dann nimm aber nicht sizeof(typ) sondern sizeof(objekt). Also sizeof *buf. Dann brauchst den Typen an der Stelle gar nicht mehr ändern.
-
Michael E. schrieb:
Dann dereferenzierst du nicht mehr unnötig in nicht definierten Bereichen rum.
Es wird nicht dereferenziert. Es werden nur zwei Adressen subtrahiert.
-
Z schrieb:
Michael E. schrieb:
Dann dereferenzierst du nicht mehr unnötig in nicht definierten Bereichen rum.
Es wird nicht dereferenziert. Es werden nur zwei Adressen subtrahiert.
Wenn er einen guten Kompiler hat, dann ist das tatsächlich der Fall. Wenn man nach der Sprache geht, findet aber bei der Angabe des Index eine Dereferenzierung statt und danach wird wieder die Adresse geholt. Daher besser gleich die Zeigerarithmetik verwenden, damit ist man auf der sicheren Seite

Grüssli
-
Dravere schrieb:
Wenn er einen guten Kompiler hat, dann ist das tatsächlich der Fall.
Wie stellt man den Unterschied fest?
-
Dieser Thread wurde von Moderator/in rüdiger aus dem Forum ANSI C in das Forum C++ verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
camper schrieb:
Dravere schrieb:
Wenn er einen guten Kompiler hat, dann ist das tatsächlich der Fall.
Wie stellt man den Unterschied fest?
Assemblercode begutachten?
-
camper schrieb:
Dravere schrieb:
Wenn er einen guten Kompiler hat, dann ist das tatsächlich der Fall.
Wie stellt man den Unterschied fest?
Am besten gar nicht und den sicheren Code verwenden, was ich ja auch nachfolgend geschrieben habe

Grüssli
-
Meiner Ansicht nach sind beide Varianten laut Standard OK.
Allerdings auch nur wegen der "one past last" Regel, die es erlaubt Zeiger zu erzeugen, die auf das Element eins hinter dem letzten Element in einem Array zeigen.
buf[1024]entspricht*(buf+1024), und das "erzeugt" erstmal nur eine Lvalue. Hier wird noch nichts wirklich dereferenziert. Von dieser Lvalue wird dann die Adresse genommen.Da es laut Standard erlaubt ist, Zeiger, die auf ein gelöschtes Objekt zeigen, mit einem neuen Wert zu überschreiben, ist auch das Erzeugen von Lvalues erlaubt, deren "Wert" nichtmehr "gelesen" werden darf. (Einen Zeiger der auf ein gelöschtes Objekt zeigt, darf man nämlich laut Standard nichtmehr auslesen, bloss noch überschreiben. Und zum überschreiben braucht man eben erstmal eine Lvalue.)
Daraus kann man jetzt zwar nicht zu 100% schliessen, dass auch das&buf[1024]in diesem Beispiel erlaubt ist, da der Fall "Zeiger mit ungültigem Inhalt" und "Element one past last" nicht ganz der selbe ist. Einmal haben wir einen Zeiger der existiert, dessen Inhalt aber nichtmehr gelesen werden darf, und einmal haben wir ein Element das gleich garnicht existiert.Ich behaupte aber trotzdem, dass es OK ist.
Und ich kann mir auch nicht vorstellen, dass es Compiler gibt, die hier ein Programm erzeugen, das nicht das tut, was man erwarten würde.
Schliesslich ist es weder nötig noch irgendwie hilfreich den Wert zu lesen. Gefragt ist ja schliesslich im Endeffekt die Adresse, und um zu der zu kommen, bringt es nichts, den Wert an dieser Adresse aus dem Speicher zu laden.
-
Aber mit ganz viel Heimtücke könnte man Fälle konstruieren, wo Element 1023 an der letzten Stelle im Speicher steht und die Adresse von Element 1024 ist dann 0, wegen Überlaufs. Dann würde es trotz allem nicht funktionieren.
-
hustbaer schrieb:
Meiner Ansicht nach sind beide Varianten laut Standard OK.
Gegenwärtig nicht. Im nächsten Standard schon.
hustbaer schrieb:
Allerdings auch nur wegen der "one past last" Regel, die es erlaubt Zeiger zu erzeugen, die auf das Element eins hinter dem letzten Element in einem Array zeigen.
Die ist erforderlich aber nicht ausreichend.
hustbaer schrieb:
buf[1024]entspricht*(buf+1024), und das "erzeugt" erstmal nur eine Lvalue.Und das ist exakt, was dereferenzieren bedeutet.
hustbaer schrieb:
Und ich kann mir auch nicht vorstellen, dass es Compiler gibt, die hier ein Programm erzeugen, das nicht das tut, was man erwarten würde.
Jedenfalls lässt sich durch Studieren des Assemblercodes nichts beweisen. Da Zeigerdereferenzierung begrifflich nur in der abstrakten Maschine sinnvoll ist, kann die Abwesenheit dieser Operation am erzeugten Code nicht demonstriert werden.
-
SeppJ schrieb:
Aber mit ganz viel Heimtücke könnte man Fälle konstruieren, wo Element 1023 an der letzten Stelle im Speicher steht und die Adresse von Element 1024 ist dann 0, wegen Überlaufs. Dann würde es trotz allem nicht funktionieren.
Ja, aber Ergebnisse von new[] und lokale oder globale Arrays werden so gelegt, daß genau das nicht der Fall ist. Besorgst Du den Speicher anders, kann komisches passieren.
Hier hat der Compiler beichar buf[1024];dafür zu sorgen, daß buf+1024>buf.
-
Es wird nicht dereferenziert, weil der Wert an der Adresse nie gebraucht wird, z.B. durch Zuweisung oder Übergabe an eine Funktion, sondern es werden ausschliesslich die Adressen betrachtet. In der Sprachdefinition mag ein "array[index]" bereits eine Dereferenzierung bedeuten, aber kein realer Compiler würde hier sofort dereferenzieren, sondern den äquivalenten Ausdruck "array+index" sehen.
-
Z schrieb:
Es wird nicht dereferenziert, weil der Wert an der Adresse nie gebraucht wird, z.B. durch Zuweisung oder Übergabe an eine Funktion, sondern es werden ausschliesslich die Adressen betrachtet. In der Sprachdefinition mag ein "array[index]" bereits eine Dereferenzierung bedeuten, aber kein realer Compiler würde hier sofort dereferenzieren, sondern den äquivalenten Ausdruck "array+index" sehen.
Das hat ja hustbaer schon gesagt und camper hat darauf geantwortet.
Laut Standard scheint es nicht okay zu sein. Es gibt schliesslich viele Fälle, welche streng genommen verboten sind, aber für die verbreiteten Compiler das erwartete Verhalten erzeugen. Und trotzdem ist es nicht schlecht, man kennt sich ein wenig mit den Grenzen des C++-Standards aus, vor allem in Hinblick auf Portabilität. Gerade bei Dingen, welche wirklich so einfach zu lösen sind wie hier, wo man eben
ptr + offsetstatt&ptr[offset]schreibt.Das gehört zu den Angelegenheiten, welche fast immer gut gehen, aber wenn nicht, hat man trotzdem ein echtes Problem.
-
@Nexus:
Lies auch die von camper verlinkte Seite. Ich verstehe das so, dass der (aktuelle) Standard diesbezüglich nicht klar formuliert ist.@SeppJ:
Das Verwenden eines Zeigers auf das "one past last" Element (z.B. als "end" Iterator), ist soweit ich weiss explizit erlaubt. Von daher darf es IMO auch keine Probleme mit "ptr + size" geben.Wie die Implementierung dafür sorgt, dass es funktioniert, ist dann wieder eine andere Sache. Und wenn man anfängt selbst Allokatoren zu schreiben, muss man wohl oder übel selbst dafür sorgen, dass alle vom Standard gegebenen Garantien auch eingehalten werden.
-
@camper:
Danke für den Link!
Ich finde es gut, dass das "bereinigt" wird.
-
hustbaer schrieb:
@Nexus:
Lies auch die von camper verlinkte Seite. Ich verstehe das so, dass der (aktuelle) Standard diesbezüglich nicht klar formuliert ist.Okay, hab den Artikel zuvor noch nicht gelesen. Die geplante Vereinheitlichung finde ich auch gut.
Im Forum hier gab es doch auch schon Unklarheiten wegen sowas:
struct bar { void foo() { // kein Memberzugriff } }; int main() { bar* obj = 0; obj->foo(); }