est-il un moyen plus facile d'afficher les champs C'est ce que je fais maintenant: p> etc ... p> est-il un moyen plus facile que d'avoir à appeler individuellement chacun d'eux? Je veux lire un fichier binaire, puis afficher la structure correspondante dans un contrôle code> richedit code> pour un petit utilitaire que je suis immobilier et n'a trouvé aucun autre moyen. Je sais comment lire des fichiers binaires et lire les valeurs dans le struct code> et leurs valeurs correspondantes dans
richedit code> contrôle?
struct code> déjà. P> p>
9 Réponses :
Je n'utilise pas C ++ Builder, de sorte que certains des détails de ceci sont susceptibles d'être un peu désactivés, mais l'idée générale devrait être au moins raisonnablement proche: la base L'idée est assez simple: un front-end pour un contrôle Richedit, qui fournit un opérateur modélisé <<. L'opérateur met un élément dans un StringStream pour le convertir en une chaîne. Il reçoit alors la chaîne résultante et l'appendez aux lignes du contrôle. Puisqu'il est modelé, il peut fonctionner avec tous les types habituels supportés par un StringStream. P> Cela a des lacunes - sans plus de travail, vous ne pourrez pas utiliser de manipulateurs pour contrôler la mise en forme des données. C'est converti en une chaîne. Étant donné qu'il utilise une chaîne pour convertir des choses aux cordes, il est probablement également un peu plus lent que votre code codant explicitement du type de chaque conversion. Dans le même temps, vous pouvez utiliser un code idiomatique assez propre, simple et idiomatique pour un investissement assez minime. P> p>
C'est bon, mais comment puis-je itération sur la structure pour effectuer ce qui précède?
@ROBOTO: Il n'y a pas grand chose que vous puissiez faire pour éviter d'itération sur les membres de la structure, à moins que ce ne soit du même type, vous pouvez également utiliser des tableaux.
Ils ne sont pas du même type (mélange d'int, uint, de char et de char *)
@Roboto: Dans ce cas, vous pouvez créer quatre tableaux (un de chaque type) puis itérer sur chaque tableau dans une boucle normale ...
Je ne pense pas que cela fonctionnera dans mon scénario ... Y a-t-il un moyen de itération sur une structure?
Non, vous ne pouvez pas vraiment itération sur une structure, bien qu'il y ait des imitations qui pourraient fonctionner. Une possibilité serait boost :: Tuple, qui permet de spécifier des membres par index, mais uniquement à la compilation (en tant que paramètres de modèle). Un autre serait de générer le code de manière externe - à l'aide du code que j'ai donné, vous pouvez avoir (par exemple) une liste de membres, et utilisez quelque chose comme AWK pour générer du code pour les afficher.
Bien que vous ne puissiez pas directement itérer sur un struct code>, vous pouvez écrire une méthode visiteur i> qui envoie chaque méthode et son nom à un objet de fonction visiteur i> . Cela présente l'avantage de créer des visiteurs à des fins différentes et de ne pas modifier le code ou la structure de l'objet d'origine (mise en page).
Je suggère de créer des méthodes modèles pour écrire dans la zone de texte:
void annotate(TRichTextEdit& textbox) { Write_To_Textbox(member1, "member1", textbox); //... }
P.s. Ajouter un #if code> pour le débogage empêcherait ce code de la libération.
Si je comprends bien correctement, le cœur de la question initiale est de savoir comment itération sur une structure. En bref, alors que Jerry Coffin a souligné dans un commentaire, cela ne peut pas être fait. Je vais essayer d'expliquer pourquoi, puis je vais essayer d'expliquer comment faire la meilleure chose à faire.
Une structure est stockée en mémoire comme une pièce monolithique de données sans métadonnées décrivant sa structure. Par exemple, la structure suivante: p> peut être représentée en mémoire en utilisant une notation hexadécimale comme suit p> où le premier 3 octets contiennent les champs de caractères, le quatrième est une valeur aléatoire utilisée pour le remplissage, et les quatre octets suivants sont la représentation Little-Endian de l'entier 122. Cette mise en page varie d'un compilateur au compilateur et au système au système. En bref, la représentation binaire ne vous dit pas quelles sont les données ou où des champs individuels sont stockés. P> Alors, comment les champs d'accès du compilateur dans des structures? Le code p> est traduit dans une instruction comme p> en d'autres termes, le compilateur code les décalages littéraux de la champs dans le code. Encore une fois, cela ne nous aide pas. P> Par conséquent, nous devons annoter la structure nous-mêmes. Cela peut être fait en ajoutant des informations à l'intérieur de la structure pour la transformer en une sorte de magasin de valeur de clé ou en ajoutant une deuxième structure. Vous ne voulez pas changer la structure d'origine, une deuxième structure est donc la voie à suivre. P> Je suppose que votre structure ne contient que des types de base: int, char, etc. Si vous êtes complexe d'autres classes dans la structure, alors je suggère d'ajouter une méthode de tostring () à leur classe de base et d'appeler cette méthode - c'est comme ça que C # et Java le font. P> Foo tmp;
#define FIELD_OFFSET(f) ((char*)&(tmp.f) - (char*)&tmp)
enum FieldType { INT_FIELD, CHAR_FIELD, OBJECT_FIELD };
struct StructMeta {
FieldType type;
size_t offset;
};
StructMeta[] metadata = {
{CHAR_FIELD, FIELD_OFFSET(a)},
{CHAR_FIELD, FIELD_OFFSET(b)},
{CHAR_FIELD, FIELD_OFFSET(c)},
{INT_FIELD, FIELD_OFFSET(i)},
{OBJECT_FIELD, FIELD_OFFSET(o)},
}
void RenderStruct(Foo* f)
{
for (int i = 0; i < sizeof(metadata)/sizeof(StructMeta); i++)
{
switch (metadata[i].type)
{
case CHAR_FIELD:
char c = *((char*)f + metadata[i].offset);
// render c
break;
case INT_FIELD:
int i = *(int*)((char*)f + metadata[i].offset);
// render i
break;
case OBJECT_FIELD:
Object* o = (object*)((char*)f + metadata[i].offset);
const char* s = o->ToString();
// render s
break;
}
}
}
C'est bien! Et si la structure contient également une structure? Je suppose que vous devez avoir des métadonnées de métadonnées ?!
Ma suggestion serait de mettre en œuvre une méthode Tostring () sur la struct ou une classe de base.
Comment imprimez-vous les noms de champs de la structure?
Étant donné que vous avez un nombre assez grand de champs dans la structure, utilisez un analyseur ou écrivez le vôtre pour générer un code source pour imprimer les membres, leurs noms et leurs valeurs. p>
comme un exercice intéressant, le temps vous-même comme vous écrivez l'utilitaire. Vous pouvez savoir que l'utilisation d'un éditeur disposant de la recherche d'expression régulière et de remplacer la capacité peut être plus rapide. P>
Sinon, jetez votre conception actuelle et adoptez un nouveau. J'ai utilisé une conception d'enregistrements et de champs. Chaque enregistrement (structure) a un vecteur d'un ou plusieurs pointeurs à un Ajouter le motif em> visiteur em> pour la lecture et l'écriture (j'appelle les lecteurs et les écrivains) et vous avez des champs et des enregistrements hautement adaptables sans changer leur contenu interne. En outre, cela conduit merveilleusement dans la programmation générique em> où vous pouvez utiliser des champs et des enregistrements sans connaître leurs types; ou avoir cela pris en charge au niveau des feuilles. P>
BTW, au moment où vous avez attendu la réponse parfaite, vous auriez pu écrire une fonction pour "itérer" ou visiter em> les membres de la structure. P> field_interface code>. Le
field_interface code> a des méthodes telles que
get_field_name () code> et
get_sql_data_type_text () code>. N'oubliez pas non plus que Java Favoris
Tostring () code> qui renvoie la valeur de champ en tant que chaîne. Cette technique vous permet d'iTerrer sur un conteneur de champs et d'imprimer leurs valeurs (en utilisant
Tostring code>) et leur nom (utilisant
get_field_name () code>). p>
Le problème de la refonte est la compatibilité à l'envers. Cela prendrait beaucoup plus de temps et d'efforts pour assurer la compatibilité à l'envers en repensant. Ce format est utilisé depuis plus de 10 ans et nous obtenons de temps en temps quelqu'un qui doit être mis à niveau depuis plus de 8 ans, le format de configuration doit donc correspondre ou que les bits ne seront plus au même endroit.
Il n'y a aucun moyen de itérer les membres d'une structure à moins que vous ne construisiez vos propres métadonnées pour décrire la structure. Le compilateur C ++ n'émet tout simplement pas l'information dont vous auriez besoin automatiquement.
Cependant, avec un peu de macro Magic, vous pouvez construire les métadonnées dont vous auriez besoin assez facilement. J'ai écrit un certain code pour le faire (en fait un contrôle personnalisé Windows soufflé complet) il y a de nombreuses années et je l'utilise toujours tout le temps. P>
Le truc de base consiste à utiliser une magie macro-magie de bit d'obtenir le compilateur vous aider à construire les métadonnées. p>
Alors, vous devez faire vos informations de type disponible lors de l'exécution. Ces métadonnées sont disponibles au moment de la compilation, mais est ensuite mis au rebut. Nous avons juste besoin d'un moyen de le sauver du compilateur. P>
explicite Metadata strong>, comme le démontre antonmarkov et John Knoeller. Vous devez maintenir en phase avec la structure, mais il a la vertu de ne pas toucher votre définition de la structure d'origine. P>
1.1 Génération de code strong>
Si votre définition de struct est assez régulière, vous pourriez être en mesure d'automatiser la génération de cette table de métadonnées en utilisant awk. P> li>
Métaprogrammation strong>: si vous ne me dérange pas de réécrire la structure (mais en laissant la mise en page même, de sorte que vous gardez la compatibilité binaire) vous pouvez obtenir le compilateur de faire la levée de lourdes pour vous . Vous pouvez utiliser Boost.tuple déclarer votre structure et itérer sur ses éléments en utilisant Boost .Fusion . p> li>
ol>
Non pas que je pense que c'est une bonne réponse, mais cela semble être inclus pour des raisons d'exhaustivité. Une approche quelque peu différente consisterait à écrire une extension de débogueur à l'aide du APIS de Windows Debugger Extension < / a>. La tâche que vous décrivez est presque parfaite pour une extension de débogueur. Je dis presque parce que je ne suis pas sûr que cela y incluait dans une version de libération est un très bon plan. Mais selon l'endroit où vous avez besoin de cette fonctionnalité, cela pourrait être une possibilité. Si cela est nécessaire "en interne" pour vos propres objectifs, cela peut fonctionner. S'il est nécessaire de fonctionner sur le site d'un client, je serais moins enclin à l'utiliser à cause des bagages supplémentaires (symboles de débogage) qui devraient être expédiés. P>
Il y a aussi un gros problème potentiel avec votre environnement. Il semble que vous utilisiez C ++ Builder version 5. Je ne suis pas au courant d'un moyen de générer des symboles de débogage de cet environnement qui fonctionnerait avec les outils de débogage de Windows. Il y a une utilitaire MAP2DBG qui fait la conversion, mais il a apparemment besoin d'au moins C ++ Builder V6. p>
Il n'y a aucun moyen de itération sur les membres d'une structure ordinaire. Vous devez fournir ces informations en dehors de votre déclaration de structure.
Vous pouvez le faire à la compilation, car certaines des réponses précédentes ont montré. Cependant, vous pouvez aussi le faire au moment de l'exécution. Ceci est similaire à la manière dont certaines bibliothèques "sérialisement" fonctionnent. P>
Vous pouvez avoir la classe suivante: p> Cette classe contient un vecteur de "classe Membres "(Memberstore :: Datainfo), chacun de l'un a: p> Vous pouvez ajouter des éléments à cette classe à l'aide de & opérateur (vous pouvez concaténer plusieurs et opérateurs). Après cela, vous pouvez parcourir les membres et les convertir à STD :: String à l'aide de son index: P>
struct StructureIWantToPrint
{
char a;
int b;
double c;
};
int main(int argc, wchar_t* argv[])
{
StructureIWantToPrint myData;
myData.a = 'b';
myData.b = 18;
myData.c = 3.9;
MemberStore myDataMembers(myData);
myDataMembers & myData.a & myData.b & myData.c;
for(size_t i=0;i<myDataMembers.size();++i) {
std::cout << myDataMembers.convert(i) << std::endl;
}
return 0;
}
boost_fusion_ADAPT_Struct_structeur code>
semble aller bien ici. Par exemple:
J'aime aussi la solution. a demandé spécifiquement comment descendre dans des champs de structure imbriqués et que tout fonctionnait .
Notez que pour les structures de modèle, on peut utiliser boost_fusion_adapt_tpl_truct .
Votre problème est-il avec le riche édition ou avec la sortie de la structure confortablement?
La structure ... Ce serait bien s'il y avait un moyen facile de parcourir la structure. À l'heure actuelle, je dois faire référence à chaque champ individuellement et il est gênant d'avoir plus de 100 lignes de code répétitif.
@Roboto: Avoir plus de 100 membres de la structure ressemble à un problème en soi. Peut-être devriez-vous poser une question sur la façon de redéfinir cette classe ...
Il n'y a pas de problème avec la structure. Il a été utilisé depuis plus de 10 ans - aucun problème. La structure contient un fichier de configuration binaire de 4 octets.
@Roboto: Je suis un peu confus. Comment quatre octets peuvent-ils sortir à plus de 100 membres?
Correction: 4 limites d'octets (c'est-à-dire quatre caractères non signés groupés), ou un int, etc .. Le fichier de configuration est d'environ 6 Ko
L'une des questions est que le compilateur connaît les noms des membres de la structure et de l'ordre, mais ne met pas cette information dans l'exécutable; Il n'est pas non plus disponible pour l'utilisateur.