Domanda

Ho una definizione della struttura di test come segue:

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

E da qualche parte lo uso in questo modo:

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

Funziona correttamente sul mio Windows: ne stampa 15 come previsto, ma è sicuro? Posso davvero essere sicuro che la variabile sia sul posto nella memoria che voglio che sia - specialmente nel caso di tali strutture combinate (ad esempio f è sul mio compilatore la quinta parola, ma è una sesta variabile)?

In caso contrario, esiste un altro modo per manipolare direttamente i membri di una struttura senza effettivamente avere un costrutto di membro di struttura nel codice?

È stato utile?

Soluzione

Sembra che tu stia facendo due domande

È sicuro trattare & amp; test come un organizzatore di 3 lunghezze?

Probabilmente è meglio evitarlo. Potrebbe trattarsi di un'azione definita nello standard C ++, ma anche se lo è, è improbabile che chiunque lavori con te capisca cosa stai facendo qui. Credo che questo non sia supportato se leggi lo standard a causa del potenziale di pad delle strutture ma non ne sono sicuro.

Esiste un modo migliore per accedere a un membro senza il suo nome?

Sì. Prova a utilizzare la offsetof macro / operatore. Ciò fornirà l'offset di memoria di un particolare membro all'interno di una struttura e ti permetterà di posizionare correttamente un punto su quel membro.

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

Un altro modo sarebbe prendere semplicemente l'indirizzo di c direttamente

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

Altri suggerimenti

No, non puoi esserne sicuro. Il compilatore è libero di introdurre il riempimento tra i membri della struttura.

Per aggiungere a JaredPar's answer , un'altra opzione solo in C ++ (non nella semplice C) è creare un oggetto puntatore-membro:

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
}

Probabilmente stai cercando la macro offsetof . Questo ti darà l'offset di byte del membro. È quindi possibile manipolare il membro a quell'offset. Nota, tuttavia, questa macro è specifica dell'implementazione. Includi stddef.h per farlo funzionare.

Probabilmente non è sicuro ed è non leggibile al 100%; rendendo così inaccettabile quel tipo di codice nel codice di produzione reale.

usa i metodi set e boost :: bind per create functor che cambierà questa variabile.

A parte i problemi di riempimento / allineamento che altre risposte hanno sollevato, il tuo codice viola le rigide regole di aliasing, il che significa che potrebbe rompersi per build ottimizzate (non sono sicuro di come MSVC faccia questo, ma GCC -O3 lo farà interrompere questo tipo di comportamento). Essenzialmente, poiché test * t e int * ptr sono di tipi diversi, il compilatore può presumere che facciano riferimento a diverse parti della memoria e può riordinare le operazioni.

Considera questa modifica minore:

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

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

L'output alla fine potrebbe essere 13 o 15 , a seconda dell'ordine delle operazioni utilizzate dal compilatore.

Secondo il paragrafo 9.2.17 dello standard, è infatti legale lanciare un pointer-to-struct in un puntatore al suo primo membro, a condizione che la struttura sia POD :

  

Un puntatore a un oggetto POD-struct,   opportunamente convertito usando a   reinterpret_cast, punta al suo   membro iniziale (o se quel membro è a   campo bit, quindi all'unità in cui   risiede) e viceversa. [Nota:   Ci potrebbe quindi essere senza nome   imbottitura all'interno di un oggetto POD-struct,   ma non all'inizio, se necessario   per ottenere un allineamento adeguato. ]

Tuttavia, lo standard non fornisce alcuna garanzia in merito al layout delle strutture - anche le strutture POD - a parte il fatto che l'indirizzo di un membro successivo sarà maggiore dell'indirizzo di un membro precedente, a condizione che non vi siano specificatori di accesso (< codice> privato: , protetto: o pubblico: ) tra di loro. Quindi, trattare la parte iniziale del tuo struct test come un array di 3 numeri interi è un comportamento tecnicamente indefinito.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top