2016-06-23 14 views
1
#include <iostream> 
using namespace std; 
int main() 
{ 
    int a=50; 
    int b=50; 
    int *ptr = &b; 
    ptr++; 
    *ptr = 40; 
    cout<<"a= "<<a<<" b= "<<b<<endl; 
    cout<<"address a "<<&a<<" address b= "<<&b<<endl; 
    return 0; 
} 

Die obigen Code druckt:undefinierte Verhalten beobachtet in C++/Speicherzuordnung

a= 50 b= 50 
address a 0x7ffdd7b1b710 address b= 0x7ffdd7b1b714 

Während, wenn ich die folgende Zeile aus dem obigen Code entfernen

cout<<"address a "<<&a<<" address b= "<<&b<<endl; 

ich Ausgabe als

a= 40 b= 50 

Mein Verständnis war, dass die Stapel wächst nach unten, so scheint die zweite Antwort die richtige zu sein. Ich bin nicht in der Lage zu verstehen, warum die print-Anweisung das Speicherlayout durcheinander bringen würde.

EDIT:

ich vergaß zu erwähnen, ich bin mit 64-Bit-x86-Maschine, mit O als ubuntu 14.04 und gcc Version 4.8.4

+7

Es ist * nur undefiniert Verhalten *. – juanchopanza

+0

In VS2005 nicht der Fall. Ich führe den oben genannten Code mit und ohne die 'cout << "Adresse eine" << .. 'Zeile und das Ergebnis ist a = 50, b = 50 in beiden Fällen. – Makif

Antwort

4

Zunächst einmal, es ist alles nicht definiertes Verhalten ist. Der C++ - Standard besagt, dass Sie Zeiger nur so lange inkrementieren können, wie Sie sich in Array-Grenzen befinden (plus ein Element danach), mit einigen Ausnahmen für Standard-Layout-Klassen, aber das ist es auch schon. In der Regel ist es also Neuland, mit Zeigern herumzuschnüffeln.

Kommen zu Ihrem tatsächlichen Code: Da Sie nie nach seiner Adresse fragen, wahrscheinlich der Compiler entweder nur a in einem Register, oder sogar gerade propagierte es als eine Konstante im gesamten Code. Aus diesem Grund berührt a niemals den Stapel und Sie können ihn nicht mit dem Zeiger beschädigen.

Beachten Sie, dass der Compiler nicht auf Push/Pop-Variablen auf dem Stack in der Reihenfolge ihrer Deklaration beschränkt ist - sie werden in der Reihenfolge neu angeordnet, in der sie passen, und tatsächlich können sie sogar im Stack-Frame (oder ersetzt werden) während der gesamten Funktion - und eine scheinbar kleine Änderung in der Funktion kann den Compiler veranlassen, das Stapellayout vollständig zu ändern. Daher sagt selbst der Vergleich der Adressen nichts über die Richtung des Stapelwachstums aus.

+0

Darüber hinaus ist es sogar in der '& a'-Version möglich, dass der Compiler in der ersten 'cout'-Zeile' 50 'inline einfügt. – melpomene

+0

@melpomene: yep, vielleicht kompiliert er mit nicht sehr aggressiven Optimierungseinstellungen. –

+0

Ich verwende keine Optimierungsflags und stimme zu, dass dies nicht die Art ist, die Stapelwachstumsrichtung zu finden. Was ihr Leute sagt, macht Sinn, aber soll es nicht so sein, wie wenn b unter einem Gedächtnis-Layout liegt - zumindest haben wir das gelernt? Ich habe versucht, die Art und Weise zu nutzen, in der Speicher in einem Programm/Stack angelegt ist und nicht genau von den Grenzen wie in Arrays und Klassen begrenzt ist. Kann ich das nicht so ausnutzen? – animentary

2

UB - Sie genommen haben einen Zeiger auf b Sie diesen Zeiger ptr++ bewegen, was bedeutet, Sie zeigen auf einen unbekannten, nicht-zugewiesenen Speicher und Sie versuchen, auf diesem Speicherbereich zu schreiben, die ein nicht definiertes Verhalten verursachen.

Auf VS 2008, Debuggen es wird Schritt-für-Schritt für diese Meldung werfen die sehr selbsterklärend :: enter image description here

+0

Ich benutze gdb und es wirft keinen Fehler, ich ging auch Schritt-für-Schritt dort, aber nichts von dieser Art kam auf. – animentary

+0

Haben Sie versucht, Valgrind zu verwenden? Ich denke, es würde helfen, aber nicht sicher.Die geworfene Nachricht ist hier nicht wichtig. Wichtig ist, dass Sie versuchen, auf den Speicher zuzugreifen, der Ihnen nicht zugewiesen ist. – Abhineet