Frage

Ich habe eine Teststrukturdefinition wie folgt:

struct test{
    int a, b, c;
    bool d, e;
    int f;
    long g, h;
};

Und irgendwo benutze ich es so:

test* t = new test;   // create the testing struct
int* ptr = (int*) t;
ptr[2] = 15;          // directly manipulate the third word
cout << t->c;         // look if it really affected the third integer

Dies funktioniert korrekt unter meinen Fenstern - es druckt 15 wie erwartet, aber ist es sicher? Kann ich mir wirklich sicher sein, dass die Variable im Speicher vor Ort ist, das ich im Speicher haben möchte - im Falle eines solchen kombinierten Strukturen (zum Beispiel f ist F auf meinem Compiler, dem fünften Wort, aber es ist eine sechste Variable)?

Wenn nicht, gibt es eine andere Möglichkeit, strukturierte Mitglieder direkt zu manipulieren, ohne tatsächlich ein Strukturmitgliedskonstrukt im Code zu haben?

War es hilfreich?

Lösung

Es sieht so aus, als würden Sie zwei Fragen stellen

Ist es sicher, als 3 -Länge -Int -Arrray zu behandeln und zu testen?

Es ist wahrscheinlich am besten, dies zu vermeiden. Dies mag eine definierte Aktion im C ++ - Standard sein, aber selbst wenn dies der Fall ist, ist es unwahrscheinlich, dass jeder, mit dem Sie arbeiten, verstehen, was Sie hier tun. Ich glaube, dies wird nicht unterstützt, wenn Sie den Standard aufgrund des Potenzials für Pad -Strukturen lesen, aber ich bin mir nicht sicher.

Gibt es einen besseren Weg, um auf ein Mitglied ohne Namen zuzugreifen?

Ja. Versuchen Sie es mit dem Offsetof Makro/Operator. Dadurch wird der Speicherversatz eines bestimmten Mitglieds innerhalb einer Struktur bereitgestellt und ermöglicht es Ihnen, einen Punkt auf dieses Mitglied korrekt zu positionieren.

size_t offset = offsetof(mystruct,c);
int* pointerToC = (int*)((char*)&someTest + offset);

Eine andere Möglichkeit wäre jedoch, einfach die Adresse von C direkt zu übernehmen

int* pointerToC = &(someTest->c);

Andere Tipps

Nein, du kannst nicht sicher sein. Der Compiler kann die Polsterung zwischen Strukturmitgliedern einführen.

Hinzufügen zu Jaredpars Antwort, Eine weitere Option nur in C ++ (nicht in einfach C) besteht darin, ein Objekt Zeiger zu Mitgliedern zu erstellen:

struct test
{
  int a, b, c;
  bool d, e;
  int f;
  long g, h;
};

int main(void)
{
  test t1, t2;

  int test::*p;  // declare p as pointing to an int member of test
  p = &test::c;  // p now points to 'c', but it's not associating with an object
  t1->*p = 3;    // sets t1.c to 3
  t2->*p = 4;    // sets t2.c to 4

  p = &test::f;
  t1->*p = 5;    // sets t1.f to 5
  t2->*p = 6;    // sets t2.f to 6
}

Sie suchen wahrscheinlich nach dem offsetof Makro. Dadurch erhalten Sie den Byte -Offset des Mitglieds. Sie können das Mitglied dann zu diesem Offset manipulieren. Beachten Sie jedoch, dass dieses Makro implementierungsspezifisch ist. Enthalten stddef.h Um es zum Laufen zu bringen.

Es ist wahrscheinlich nicht sicher und zu 100% nicht lesbar. So machen Sie diese Art von Code inakzeptabel im Produktionscode im realen Leben inakzeptabel.

Verwenden Sie SET -Methoden und Boost :: Bind for Create Functor, die diese Variable ändern.

Abgesehen von Padding-/Ausrichtungsproblemen, die andere Antworten angesprochen haben, verstößt Ihr Code gegen strenge Aliasing -Regeln, was bedeutet -O3 wird diese Art von Verhalten brechen). Im Wesentlichen, weil test *t und int *ptr von verschiedenen Typen, der Compiler kann annehmen, dass er auf verschiedene Teile des Speichers verweist, und er kann Operationen neu ordnen.

Betrachten Sie diese geringfügige Änderung:

test* t = new test;
int* ptr = (int*) t;

t->c = 13;
ptr[2] = 15;
cout << t->c;

Die Ausgabe am Ende könnte entweder sein 13 oder 15, Abhängig von der Reihenfolge der Operationen verwendet der Compiler.

Nach Absatz 9.2.17 des Standard Pod:

Ein Zeiger auf ein Pod-Struct-Objekt, das mit einem neuinterpret_cast geeignet konvertiert wird, zeigt auf sein ursprüngliches Mitglied (oder wenn dieses Mitglied ein Bitfeld ist, dann auf die Einheit, in der es sich befindet) und umgekehrt. [Hinweis: In einem Pod-Struct-Objekt kann daher nicht zu Beginn unbenannt sein, um eine angemessene Ausrichtung zu erreichen, jedoch nicht zu Beginn.

Der Standard bietet jedoch keine Garantien für das Layout von Strukturen - sogar POD -Strukturen -, außer dass die Adresse eines späteren Mitglieds größer ist als die Adresse eines früheren Mitglieds, vorausgesetzt, es gibt keine Zugriffsspezifizierer (private:, protected: oder public:) zwischen ihnen. Also behandeln Sie den ersten Teil Ihres struct test Als Array von 3 Ganzzahlen ist technisch undefiniertes Verhalten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top