Tilgang struct medlemmer direkte

stemmer
1

Jeg har en test struct definisjon som følger:

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

Og et sted jeg bruker det på denne måten:

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

Dette fungerer riktig på min Windows - den skriver ut 15 som forventet, men er det trygt? Kan jeg være helt sikker på at variabelen er på stedet i minnet jeg vil den skal være - expecially i tilfelle slike kombinerte structs (for eksempel f er på min kompilatoren femte ordet, men det er en sjette variabel)?

Hvis ikke, er det noen annen måte å manipulere struct medlemmer direkte uten egentlig å struct-> medlem konstruere i koden?

Publisert på 08/03/2009 klokken 14:59
kilden bruker
På andre språk...                            


8 svar

stemmer
13

Det ser ut som du spør to spørsmål

Er det trygt å behandle og testen som en 3 lengde int arrray?

Det er nok best å unngå dette. Dette kan være en definert handling i C ++ standard, men selv om det er det, er det lite sannsynlig at alle du jobber med vil forstå hva du gjør her. Jeg tror dette støttes ikke hvis du leser standarden på grunn av muligheten til å pad structs men jeg er ikke sikker.

Finnes det en bedre måte å få tilgang til et medlem uten det navnet?

Ja. Prøv å bruke offsetof makro / operatør. Dette vil gi minnet oppveid av et bestemt medlem i en struktur og vil tillate deg å korrekt plassere et poeng å medlemmet.

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

En annen måte skjønt ville være å bare ta adressen til c direkte

int* pointerToC = &(someTest->c);
Svarte 08/03/2009 kl. 15:08
kilden bruker

stemmer
5

Nei du kan ikke være sikker. Kompilatoren er fritt til å innføre polstring mellom lagselementer.

Svarte 08/03/2009 kl. 15:04
kilden bruker

stemmer
4

For å legge til JaredPar svar , bare (ikke i vanlig C) er et annet alternativ i C ++ for å lage en peker til medlem objekt:

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
}
Svarte 08/03/2009 kl. 15:52
kilden bruker

stemmer
2

Du er sannsynligvis på jakt etter den offsetofmakro. Dette får du byte forskyvning av medlemmet. Du kan deretter manipulere medlem på at offset. Merk skjønt, er denne makroen implementering spesifikke. Inkluder stddef.hå få det til å fungere.

Svarte 08/03/2009 kl. 15:12
kilden bruker

stemmer
1

Det er nok ikke trygt, og er 100% un-lesbar; dermed gjøre den slags kode uakseptabelt i det virkelige liv produksjonskode.

Svarte 08/03/2009 kl. 15:09
kilden bruker

stemmer
0

Ifølge punkt 9.2.17 av standarden, er det faktisk lovlig å kaste en peker til struct til en peker til sitt første medlem, og gir struct er POD :

En peker til en POD-struct gjenstand, hvilke hensiktsmessig omdannes ved hjelp av en reinterpret_cast, peker til sin utgangselement (eller hvis det medlem er en bit-felt, og deretter til den enhet i hvilken det befinner seg) og vice versa. [Merk: Det kan derfor være anonym padding i en POD-struct objekt, men ikke i begynnelsen, som er nødvendig for å oppnå riktig justering. ]

Men gjør standard ingen garantier om utformingen av structs - selv POD structs - annet enn at adressen til et senere medlem vil være større enn adressen til et tidligere medlem, forutsatt at det er ingen tilgang til byggebransjen ( private:, protected:eller public:) mellom dem. Så, behandle den første delen av din struct testsom en matrise av 3 heltall er teknisk udefinert oppførsel.

Svarte 10/03/2009 kl. 17:03
kilden bruker

stemmer
0

Bortsett fra padding / innretting problemer andre svar har brakt opp, bryter koden strenge aliasing regler, noe som betyr at det kan bryte for optimalisert bygger (ikke sikker på hvordan MSVC gjør dette, men GCC -O3vil bryte på denne typen atferd). I hovedsak på grunn test *tog int *ptrer av forskjellige typer, kan kompilatoren antar de peker på ulike deler av hukommelsen, og det kan omorganisere driften.

Tenk på dette mindre endring:

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

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

Utgangen ved enden kan være enten 13eller 15, avhengig av rekkefølgen av operasjoner kompilatoren bruker.

Svarte 08/03/2009 kl. 16:18
kilden bruker

stemmer
0

bruke sett metoder og øke :: bind for skape funktor som vil forandre denne variabelen.

Svarte 08/03/2009 kl. 15:34
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more