Domanda

Nelle seguenti righe di codice, devo regolare il puntatore pm di un offset in byte in uno dei suoi campi. C'è un modo migliore / più semplice per farlo, che lanciare incessantemente avanti e indietro da char * e PartitionMap * in modo che l'aritmetica del puntatore funzioni ancora?

PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
    pm = (PartitionMap *)(((char *)pm) + pm->partitionMapLength);
}
return pm;

Per coloro che non riescono a sottrarsi al codice, scorre ciclicamente attraverso descrittori di lunghezza variabile in un buffer che eredita da PartitionMap .

Anche per gli interessati, partitionMapLength restituisce sempre le lunghezze supportate dal sistema su cui è in esecuzione. I dati che sto attraversando sono conformi alla UDF .

È stato utile?

Soluzione

Uso spesso questi modelli per questo:

    template<typename T>
    T *add_pointer(T *p, unsigned int n) {
            return reinterpret_cast<T *>(reinterpret_cast<char *>(p) + n);
    }

    template<typename T>
    const T *add_pointer(const T *p, unsigned int n) {
            return reinterpret_cast<const T *>(reinterpret_cast<const char *>(p) + n);
    }

Mantengono il tipo, ma aggiungono singoli byte, ad esempio:

T *x = add_pointer(x, 1); // increments x by one byte, regardless of the type of x

Altri suggerimenti

Il cast è l'unico modo, che si tratti di un carattere * o intptr_t o di un altro tipo, e quindi del tuo tipo finale.

Ovviamente puoi semplicemente mantenere due variabili: un char * per scorrere il buffer e un PartitionMap * per accedervi. Rende un po 'più chiaro cosa sta succedendo.

for (char *ptr = ??, pm = (PartitionMap *)ptr ; index > 0 ; --index)
{
    ptr += pm->partitionMapLength;
    pm = (PartitionMap *)ptr;
}
return pm;

Come altri hanno già detto, hai bisogno dei cast, ma puoi nascondere la bruttezza in una macro o funzione. Tuttavia, un'altra cosa da tenere a mente sono i requisiti di allineamento. Sulla maggior parte dei processori non è possibile semplicemente incrementare un puntatore a un tipo di un numero arbitrario di byte e riportare il risultato in un puntatore al tipo originale senza problemi di accesso alla struttura tramite il nuovo puntatore a causa di un disallineamento.

Una delle poche architetture (anche se si tratta della più popolare) che ti permetterà di cavartela è l'architettura x86. Tuttavia, anche se stai scrivendo per Windows, ti consigliamo di tenere conto di questo problema: Win64 applica i requisiti di allineamento.

Quindi anche l'accesso al membro partitionMapLength tramite il puntatore potrebbe causare l'arresto anomalo del programma.

Potresti essere in grado di aggirare facilmente questo problema usando un'estensione del compilatore come __unaligned su Windows:

PartitionMap __unaliged *pm(reinterpret_cast<PartitionMap *>(partitionMaps));
for ( ; index > 0 ; --index)
{
    pm = (PartitionMap __unaligned *)(((char *)pm) + pm->partitionMapLength);
}
return pm;

Oppure puoi copiare i dati potenzialmente non allineati in una struttura correttamente allineata:

PartitionMap *pm(reinterpret_cast<PartitionMap *>(partitionMaps));

char* p = reinterpret_cast<char*>( pm);

ParititionMap tmpMap;
for ( ; index > 0 ; --index)
{

    p += pm->partitionMapLength;

    memcpy( &tmpMap, p, sizeof( newMap));
    pm = &tmpMap;
}

// you may need a more spohisticated copy to return something useful
size_t siz = pm->partitionMapLength;
pm = reinterpret_cast<PartitionMap*>( malloc( siz));
if (pm) {
    memcpy( pm, p, siz);
}
return pm;

Il casting deve essere fatto, ma rende il codice quasi illeggibile. Per motivi di leggibilità, isolalo in una funzione inline statico .

Ciò che mi sconcerta è perché hai 'partitionMapLength' in byte?

Non sarebbe meglio se fosse nelle unità 'partitionMap' da quando lo hai lanciato?

PartitionMap *pmBase(reinterpret_cast<PartitionMap *>(partitionMaps));
PartitionMap *pm;
...
pm = pmBase + index; // just guessing about your 'index' variable here

Sia C che C ++ ti consentono di scorrere attraverso un array tramite puntatori e ++ :

#include <iostream>

int[] arry = { 0, 1, 2, 3 };
int* ptr = arry;
while (*ptr != 3) {
    std::cout << *ptr << '\n';
    ++ptr;
}

Per far funzionare tutto questo, l'aggiunta ai puntatori è definita per prendere l'indirizzo di memoria memorizzato nel puntatore e quindi aggiungere la dimensione di qualunque tipo sia il valore ogni volta che il valore viene aggiunto. Ad esempio, nel nostro esempio ++ ptr aggiunge 1 * sizeof (int) all'indirizzo di memoria memorizzato in ptr .

Se si dispone di un puntatore a un tipo e si desidera avanzare di un determinato numero di byte da quel punto, l'unico modo per farlo è eseguire il cast su char * (perché sizeof (char) è definito come uno).

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