Question

Dans les lignes de code suivantes, je dois ajuster le pointeur pm par un décalage en octets dans l'un de ses champs. Pour ce faire, existe-t-il un moyen plus simple et plus simple que de continuer à faire des allers-retours entre char * et PartitionMap * tels que l'arithmétique du pointeur fonctionne toujours?

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

Pour ceux qui ne peuvent pas utiliser le code, cela passe en revue les descripteurs de longueur variable dans un tampon hérité de PartitionMap .

Également pour les personnes concernées, partitionMapLength renvoie toujours les longueurs prises en charge par le système sur lequel il s'exécute. Les données que je traverse sont conformes à la spécification UDF .

Était-ce utile?

La solution

J'utilise souvent ces modèles pour cela:

    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);
    }

Ils conservent le type, mais leur ajoutent des octets simples, par exemple:

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

Autres conseils

La diffusion est le seul moyen, que ce soit pour un char *, un intptr_t ou un autre type similaire, puis pour votre dernier type.

Vous pouvez bien sûr ne conserver que deux variables: un char * pour parcourir le tampon et un PartitionMap * pour y accéder. Rend un peu plus clair ce qui se passe.

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

Comme d'autres l'ont mentionné, vous avez besoin des transtypes, mais vous pouvez masquer la laideur d'une macro ou d'une fonction. Cependant, il faut également garder à l’esprit les exigences d’alignement. Sur la plupart des processeurs, vous ne pouvez pas simplement incrémenter un pointeur sur un type d'un nombre d'octets arbitraire et reconvertir le résultat en pointeur sur le type d'origine sans problèmes pour accéder à la structure via le nouveau pointeur en raison d'un mauvais alignement.

L’architecture x86 est l’une des rares architectures (même s’il s’agit de la plus populaire) qui vous permettra de vous en sortir. Toutefois, même si vous écrivez pour Windows, vous voudrez bien prendre en compte ce problème: Win64 applique les conditions d’alignement requises.

Ainsi, même l'accès au membre partitionMapLength par l'intermédiaire du pointeur pourrait planter votre programme.

Vous pourrez peut-être facilement contourner ce problème en utilisant une extension de compilateur telle que __ unaligned sous Windows:

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

Vous pouvez également copier les données potentiellement non alignées dans une structure correctement alignée:

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;

Le casting doit être fait, mais le code est presque illisible. Par souci de lisibilité, isolez-le dans une fonction static inline .

Ce qui me rend perplexe, c’est pourquoi vous avez "partitionMapLength" en octets?

Ne serait-il pas préférable qu'il se trouve dans les unités 'partitionMap' puisque vous le lancez de toute façon?

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

C et C ++ vous permettent tous les deux de parcourir un tableau via des pointeurs et ++ :

#include <iostream>

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

Pour que cela fonctionne, il est défini d'ajouter aux pointeurs l'adresse de mémoire stockée dans le pointeur, puis d'ajouter le sizeof quel que soit le type, multiplié par la valeur ajoutée. Par exemple, dans notre exemple, ++ ptr ajoute 1 * sizeof (int) à l'adresse de la mémoire stockée dans ptr .

Si vous avez un pointeur sur un type et que vous souhaitez avancer d'un nombre d'octets particulier à partir de cet emplacement, le seul moyen de le faire est de transtyper en char * (car sizeof (char) est défini comme étant un).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top