2010-04-08 5 views
0

Est-il possible d'accéder à un membre individuel d'une structure ou d'une classe sans connaître le nom de ses variables membres? Je voudrais faire un "offsetof (struct, tyname)" sans avoir le nom de la structure ou le nom de la variable membre codé en dur parmi d'autres choses. merci.Accès aux membres de structures à l'exécution

+3

Vous voulez un membre de quelque chose que vous ne savez pas d'un nom que vous ne connaissez pas. Que pensez-vous que vous pouvez faire avec? Dites-nous ce que vous voulez faire, pas ce que vous pensez devoir faire. – GManNickG

Répondre

4

Bien sûr. Si vous avez une structure et que vous connaissez le décalage et le type de la variable membre, vous pouvez y accéder en utilisant des pointeurs.

struct my_struct { 
    int member1; 
    char member2; 
    short member3; 
    char member4; 
} 

... 

struct my_struct obj; 
short member3 = *((short*)((char*)&obj + 5)); 

qui va obtenir la valeur de member3, qui est de 5 octets depuis le début de obj sur un ordinateur x86. Cependant, vous voulez être prudent. Tout d'abord, si la structure change, vos données seront corrompues. Nous jetons partout, donc vous n'obtenez aucun type de sécurité, et le compilateur ne vous avertira pas si quelque chose ne va pas. Vous devrez également vous assurer que le compilateur n'emballe pas la structure pour aligner les variables sur les limites des mots, sinon le décalage changera.

Ce n'est pas une chose agréable à faire, et je l'éviterais si j'étais vous, mais oui, cela peut être fait.

+1

Il est probablement décalé de 6 octets - parce que 'short 'est généralement aligné sur un multiple de 2 octets. Il y a quelques lacunes dans votre structure, et probablement 'sizeof (struct my_struct) == 12'. –

+0

Oui, je viens d'écrire un programme pour le découvrir et on dirait que tu as raison. C'est le danger: il est * habituellement * aligné sur un multiple de 2 octets, mais pas toujours. Salutations pour le rendre limpide. –

+2

Vous devriez lancer 'char *', pas 'void *', puisque 'sizeof (char) == 1'. Le standard C ne définit pas 'sizeof (void *)', donc faire l'arithmétique du pointeur avec 'void *' est un comportement indéfini. En guise d'extension, gcc vous permet de le faire avec 'sizeof (void *) == 1', mais il émet un avertissement quand il le fait. –

0

Quelque part dans votre code, vous devez référencer le membre de données dans la structure. Cependant, vous pouvez créer une variable qui est un pointeur vers un membre de données struct et à partir de là, vous n'avez plus besoin de le référencer par son nom.

struct foo 
{ 
    int member1; 
    int member2; 
}; 

typedef int (foo::*intMemberOfFoo); 

intMemberOfFoo getMember() 
{ 
    if (rand() > RAND_MAX/2) return &foo::member1; 
    else return &foo::member2; 
} 

foo f; 
void do_somthing() 
{ 
    intMemberOfFoo m = getMember(); 
    f.*m = 0; 
} 
1

C et C++ sont des langages compilés sans fonctionnalités de "réflexion" intégrées. Cela signifie que, indépendamment de ce que vous faites et de la façon dont vous le faites, le chemin commencera toujours d'une manière ou d'une autre à partir d'une valeur codée en dur, que ce soit un nom de membre ou une valeur de décalage à la compilation. Cela signifie que si vous voulez sélectionner un membre struct basé sur une clé d'exécution, vous n'avez pas d'autre choix que de créer manuellement un mappage qui mapperait la valeur de clé à quelque chose qui identifie un membre struct struct.

En C++, afin d'identifier un membre struct au moment de l'exécution, vous pouvez utiliser cette fonctionnalité comme pointeurs vers membres. En C, votre seul choix est d'utiliser une valeur de décalage.

Un autre problème est, bien sûr, de spécifier le type des membres, si vos membres peuvent avoir différents types. Mais vous n'avez fourni aucun détail à ce sujet, et je ne peux donc pas dire si vous avez besoin de le faire ou non.

1

Nous avons eu un problème similaire il y a quelques années: Une énorme structure d'informations de configuration sur laquelle nous voulions réfléchir. Nous avons donc écrit un script Perl pour trouver le struct, analyser ses membres, et la sortie d'un fichier C++ qui ressemblait à:

struct ConfField 
{ const char* name; 
    int type; 
    size_t offset; 
}; 

ConfField confFields[] = { 
    { "version", eUInt32, 0 }, 
    { "seqID", eUInt32, 4 }, 
    { "timestamp", eUInt64, 8 }, 
    // ... lots more ... 
    { 0, 0, 0 } 
}; 

Et nous avions alimentons le script avec la sortie de gcc -E.

De nos jours, je comprends que gccxml peut produire un fichier XML représentant n'importe quelle source C++ que gcc peut compiler, puisqu'il utilise réellement le front-end g ++ pour effectuer l'analyse. Je recommande donc de l'associer à un script d'analyse XML (j'utiliserais Python avec la bibliothèque lxml) pour trouver tout ce que vous avez toujours voulu savoir sur votre source C++.

0

La réponse technique est 'oui' car C++ est complet à Turing et vous pouvez faire presque n'importe quoi si vous essayez assez fort. La réponse la plus pratique est probablement «non», car il n'y a pas de manière sûre et facile de faire exactement ce que vous voulez.

Je suis d'accord avec GMan. Qu'est-ce que vous essayez exactement de faire qui vous fait penser que vous avez besoin de cette technique?

0

Eh bien, vous devrez d'abord configurer certaines choses, mais cela peut être fait. L'expansion de la réponse de Samir

struct my_struct { 
    int member1; 
    char member2; 
    short member3; 
    char member4; 
} 

vous pouvez créer une table des décalages:

my_struct tmp; 
int my_struct_offsets[4]={ 
    0, 
    (char*)&(tmp.member2)-(char*)&(tmp.member1), 
    (char*)&(tmp.member3)-(char*)&(tmp.member1), 
    (char*)&(tmp.member4)-(char*)&(tmp.member1) 
} 

cela prendra en compte différents alignements sur des systèmes différents

Questions connexes