2016-09-30 7 views
0

ich Kompilieren der folgenden mit -O0 (letzten gcc/Klirren) und beide geben Sie mir eine Antwort erwarte ich nicht.Pointer-Arithmetik vom Compiler ignoriert

#include <iostream> 

struct xy{ 
    int x,y; 
}; 


int main() 
{ 
    xy a{1,2}; 

    int x{1}; 
    int y{2}; 

    int *ptr1=&a.x; 
    int *ptr2=&x; 

    ptr1++; // I now point to a.y! 
    (*ptr1)++; // I now incremented a.y to 3 

    ptr2++; // I now point to y! 
    (*ptr2)++; // I now incremented y to 3 

    std::cout << "a.y=" << a.y << " ptr1=" << *ptr1 << '\n'; 
    std::cout << "y= " << y << " ptr2=" << *ptr2 << '\n'; 
} 

Ausgang:

a.y=3 ptr1=3 
y= 2 ptr2=2 

Also dieser Zugriff mit Zeigern auf Nicht-Klassen-Variablen vom Compiler optimiert-out wird.

ich auch versucht, die int zu markieren und * als volatiles int, aber es hat keinen Unterschied machen.

Welchen Teil des Standards fehlt mir/warum darf der Compiler dies tun?

Coliru Schnipsel unter: http://coliru.stacked-crooked.com/a/ed0757a6621c37a9

+1

Sie können Zeigerarithmetik wie diese nicht für Elemente verwenden, die keine Elemente eines Arrays sind. Es ist undefiniertes Verhalten. – juanchopanza

+0

@juanchopanza Sie können, aber es gibt nur so viel, was Sie mit diesem Zeiger tun können. – NathanOliver

+1

@NathanOliver Ich sagte du kannst es nicht benutzen * so * :-) – juanchopanza

Antwort

4

Im ersten Fall handelt mit den Teilnehmern den Teil, den Sie zu ignorieren, ist der Compiler in jede Menge Polsterung hinzufügen wird. Wegen dieses Inkrements muss ein Zeiger auf ein Mitglied Ihnen nicht das nächste Mitglied geben.

Der zweite Teil des Standard Sie fehlen ist es illegal ist, auf Speicher zuzugreifen, obwohl ein Zeiger auf, was es nicht darauf nicht zu. Auch wenn y möglicherweise im Speicher vorhanden ist, darf der Zeiger nicht darauf zugreifen. Es ist erlaubt, auf x zuzugreifen und es ist erlaubt, zu vergleichen, um zu sehen, ob es eine x Vergangenheit ist, aber es kann die x Adresse nicht dereferenzieren.

+0

Als eine Klasse mit nur Ints, ist es nicht garantiert, POD zu sein und so in diesem Fall genau die gleiche Speicherstruktur wie Int a [2]? Ich glaube nicht, dass der Compiler das tun darf, selbst wenn man die Ausrichtungsanforderungen berücksichtigt. – nunojpg

+1

@nunojpg [class.mem] states * Wenn ein Standard-Layout-Klassenobjekt über nicht statische Datenmember verfügt, entspricht seine Adresse der Adresse seines ersten nicht statischen Datenmembers.Andernfalls entspricht seine Adresse der Adresse seines ersten Unterobjekts für die Basisklasse (falls vorhanden). [Hinweis: Es kann daher in einem Standard-Layout-Strukturobjekt ein unbenanntes Padding geben, jedoch nicht am Anfang, um eine angemessene Ausrichtung zu erreichen. -Hinweis] *, so dass es Padding geben kann. – NathanOliver

3

Zeigerarithmetik ist nur gültig in Arrays. Sie können y nicht erreichen, indem Sie einen Zeiger auf x inzementieren. Das Verhalten Ihres Programms ist undefined. Ihre Aussage

ptr1++; // I now point to a.y!

ist einfach falsch. Denken Sie daran, dass ein Compiler eine beliebige Menge Padding zwischen den Elementen in Ihrem struct einfügen darf.

Genauer gesagt, können Sie einen Zeiger auf einen hinter der Adresse eines Skalars setzen, aber Sie dürfen nicht dereferenzieren es. zwischen den Mitgliedern eines Objekts und am Ende des Objekts

Verwandte Themen