La réflexion de soutien en C
Je sais qu'il n'est pas pris en charge, mais je me demande si il y a des trucs autour d'elle. Des conseils à donner?
- J'ai vraiment des doutes.
- Si vous voulez réflexion, le C et le C++ sont de mauvaises langues pour vous. C'est contraire à leur philosophie de "vous n'avez pas à payer pour ce que vous n'utilisez pas."
- Vous pouvez obtenir les effets de réflexion en utilisant des mécanismes à l'extérieur de fo le C/C++ langues. Voir les autres réponses.
- La chose que je suis en train de faire est de trouver ce que les paramètres d'une fonction avant d'appeler dlsym(3) . Merci pour les réponses
- ensuite, vous avez besoin d'un moyen de extact le paramètre (nom?) l'ordre et le type d'informations à partir du code source. C de ne pas le faire. Vous avez à l'étape de l'extérieur de la C de la langue. Ce qui est pratique. Voir les autres réponses.
- La mise en œuvre de base COM interfaces pourrait apporter un peu de réflexion dans votre code.
Vous devez vous connecter pour publier un commentaire.
Réflexion en général est un moyen pour un programme pour analyser la structure d'un code.
Cette analyse est utilisée pour modifier le comportement effectif du code.
Réflexion que l'analyse est généralement très faible; en général, il ne peut fournir l'accès à la fonction et les noms de champ. Cette faiblesse vient de la langue des maîtres d'œuvre essentiellement de ne pas vouloir faire le plein code source disponible au moment de l'exécution, avec les routines d'analyse pour en extraire ce que l'on veut à partir du code source.
Une autre approche est de s'attaquer à l'analyse du programme sur la tête, à l'aide d'un programme solide de l'outil d'analyse, par exemple, que l'on peut analyser le texte source exactement de la manière dont le compilateur t-il.
(Souvent, les gens proposer à des abus, le compilateur lui-même pour ce faire, mais qui, généralement, ne fonctionne pas; le compilateur machines se veut être un compilateur et il est sacrément difficile à plier à d'autres fins).
Ce qui est nécessaire est un outil qui:
(Il est utile si l'ASTs conserver des commentaires et d'autres détails de la source
code de mise en page tels que les numéros de colonne, littéral radix valeurs, etc.)
(en général, par la révision de l'ASTs qui représentent l'analyse de code)
la version révisée de la ASTs.
À l'aide de ces machines, on met en oeuvre l'analyse, quel que soit le niveau de détail est nécessaire, et puis transforme le code pour obtenir l'effet que l'exécution de réflexion permettrait de réaliser.
Il ya plusieurs avantages importants:
limité par ce que l'exécution de la réflexion ne peut le faire)
que se limiter à ce qu'une langue spécifique de mise en œuvre fournit.
Si vous n'avez pas besoin de réflexion, vous n'avez pas besoin de ces machines. Et votre langue
n'a pas besoin d'avoir le bagage intellectuel de la faiblesse de la réflexion construite en.
Voir notre Logiciel DMS de Réingénierie, Trousse à outils pour un système qui peut faire tout le dessus de C, Java, COBOL, et surtout pour le C++.
Le compilateur va probablement éventuellement générer des "symboles de débogage du fichier", ce qui d'un débogueur pouvez utiliser pour vous aider à déboguer le code. L'éditeur de liens peut également générer une "carte" dossier de.
Un truc/astuce peut être de générer puis de lire ces fichiers.
Sur la base des réponses à Comment puis-je ajouter de la réflexion pour une application C++? (Débordement De Pile) et le fait que C++ est considéré comme une "surcouche" de C, je dirais que vous êtes hors de la chance.
Il y a aussi une belle et longue réponse sur pourquoi C++ n'ont pas de réflexion (Débordement de Pile).
Trucs et astuces existe toujours. Jetez un oeil à Metaresc bibliothèque https://github.com/alexanderchuranov/Metaresc
Il fournit une interface pour les types de déclaration qui permettra également de générer des méta-données pour le type. Basés sur des méta-données, vous pouvez facilement sérialiser/désérialiser des objets de n'importe quelle complexité. Hors de la boîte, vous pouvez sérialiser/désérialiser des données XML, JSON, XDR, Lisp comme la notation, C-init notation.
Voici un exemple simple:
Ce programme permettra de sortie
Bibliothèque fonctionne très bien pour la dernière version de gcc et clang.
J'avais besoin de réflexion dans un tas de
struct
s dans un projet C++.J'ai créé un fichier xml avec la description de toutes ces structures - heureusement, les champs, les types de types primitifs.
J'ai utilisé un modèle (pas C++
template
) pour générer automatiquement uneclass
pour chaquestruct
avec des méthodes setter/getter.Dans chaque
class
j'ai utilisé une carte d'associer des noms de chaîne et les membres de la classe (des pointeurs pour les membres).Je ne regrette pas du tout l'utilisation de la réflexion, car il a ouvert de nouvelles voies pour la conception de ma fonctionnalités de base que je ne pouvais même pas imaginer sans réflexion.
(BTW, c'était un externe générateur de rapport pour un programme qui utilise un raw base de données)
Donc, j'ai utilisé la génération de code, des pointeurs de fonction et des cartes pour simuler la réflexion.
Vous auriez besoin de le mettre en œuvre à partir de vous-même à partir du sol. En ligne droite C, il n'y a pas d'informations d'exécution que ce soit gardé sur la structure et les types de composé. Les métadonnées n'existe tout simplement pas dans la norme.
Je sais que des options suivantes, mais que tous viennent à leur coût et beaucoup de limites:
libdl
(#include <dfcln.h>
)objdump
ounm
Je vais utiliser un peu de test de l'unité de cadres comme exemples plus bas, en raison de test automatique de découverte pour les infrastructures de test unitaire est un exemple typique où la réflexion est très pratique, et c'est quelque chose que la plupart des infrastructures de test unitaire pour C tomber à court de.
À l'aide de
libdl
(#include <dfcln.h>
) (POSIX)Si vous êtes sur un environnement POSIX, un peu de réflexion peut être fait en utilisant
libdl
. Les Plugins sont développés de cette façon.Utilisation
dans votre code source et lien avec
-ldl
.Vous avez accès aux fonctions
dlopen()
,dlerror()
,dlsym()
etdlclose()
avec lequel vous pouvez charger et accès /run objets partagés au moment de l'exécution. Cependant, cela ne vous donne pas un accès facile à la table des symboles.Un autre inconvénient de cette approche est que vous avez essentiellement limiter la réflexion à des objets chargés bibliothèque dynamique (objet partagé chargés lors de l'exécution via
dlopen()
).De course
nm
ouobjdump
Vous pourriez exécuter
nm
ouobjdump
pour afficher la table de symboles et d'analyser les données en sortie.Pour moi,
nm -P --defined-only -g xyz.o
donne de bons résultats, et l'analyse de la sortie est trivial.Vous seriez intéressé dans le premier mot de chaque ligne, qui est le nom du symbole, et peut-être la seconde, qui est le type de section.
Si vous ne connaissez pas le nom de l'objet dans certains de manière statique, c'est à dire que l'objet est en fait un objet partagé, au moins sur Linux ensuite, vous pourriez voulez sauter le symbole dont le nom commence par '_'.
objdump
,nm
ou des outils similaires sont également souvent disponibles à l'extérieur de POSIX environnements.L'analyse des fichiers de l'objet vous-même
Vous pu analyser des fichiers de l'objet vous-même. Vous ne voulez probablement pas à la mettre en œuvre à partir de zéro, mais utiliser une bibliothèque existante pour que. C'est de cette façon
nm
,objdump
et mêmelibdl
sont mis en œuvre. Vous pouviez regarder le code source denm
,objdump
etlibdl
et les bibliothèques qu'ils utilisent afin de savoir comment ils font ce qu'ils font.Impliquant un Analyseur
Vous pourriez écrire un analyseur et un generateur de code qui génère le nécessaire réfléchissant de l'information au moment de la compilation et la stocke dans le fichier de l'objet. Ensuite, vous avez beaucoup de liberté et pourrait même mettre en œuvre des formes primitives d'annotations. C'est ce que certains de l'unité de frameworks de test comme AceUnit faire.
J'ai trouvé que l'écriture d'un analyseur qui couvre straight-forward de la syntaxe C est assez banale. Écrire un analyseur syntaxique qui comprend vraiment C et peut traiter tous les cas n'est PAS banal.
Donc, cela a des limites qui dépendent de la façon dont exotiques la syntaxe C est que vous voulez réfléchir sur.
"Abuse" de l'éditeur de liens pour générer symbole tableaux
Vous pourriez mettre des références à des symboles qui vous voulez réfléchir dans une section spéciale et l'utilisation d'un linker configuration à émettre de la section limites, alors vous pouvez y accéder en C.
J'ai décrit ici N-l'injection de Dépendance dans C - de meilleur moyen que de l'éditeur de liens définis par des tableaux? comment cela fonctionne.
Mais attention, c'est en fonction de beaucoup de choses et pas très portable. J'ai seulement essayé cela avec
GCC
/ld
, et je sais qu'il ne fonctionne pas avec tous les compilateurs /linkers. Aussi, il est presque garanti que l'élimination du code mort ne détecte pas comment vous appelez ça, donc si vous utilisez l'élimination du code mort, vous devez ajouter tous les réfléchie des symboles comme des points d'entrée.Pièges
Pour certains des mécanismes l'élimination du code mort peut être un problème, en particulier lorsque vous avez des "abus" de l'éditeur de liens pour générer un symbole de tableaux. Il peut être contourné en disant à la réflexion des symboles comme points d'entrée pour l'éditeur de liens, et en fonction de la quantité de symboles cela peut être ni gentil ni pratique.
Conclusion
Combinant
nm
etlibdl
peut réellement donner de bons résultats. La combinaison peut être presque aussi puissant que le niveau de Réflexion utilisé par JUnit 3.x en Java. Le niveau de réflexion donnée est suffisante pour mettre en œuvre un JUnit 3.x-style unit test framework pour C, y compris les tests de cas de découverte par la convention de nommage.Impliquant un analyseur est plus de travail et limitée à des objets que vous compilez vous-même, mais vous donne plus de puissance et de liberté. Le niveau de réflexion peut être suffisante pour mettre en œuvre un JUnit 4.x-style unit test framework pour C, y compris les tests de cas de découverte par les annotations. AceUnit est une unit test framework pour C qui fait exactement cela.
Combinant l'analyse et l'éditeur de liens pour générer symbole tableaux peuvent donner de très bons résultats - si votre environnement est tellement sous votre contrôle que vous pouvez vous assurer que le travail avec l'éditeur de liens qui fonctionne pour vous.
Et bien sûr, vous pouvez combiner toutes les méthodes de coudre ensemble les morceaux jusqu'à ce qu'ils correspondent à vos besoins.
Juste faire quel que soit le type de incrustée de table, un arbre, une liste liée ou quelle que soit la collection, vous êtes à l'aise dans la gestion ou la trouver pour être efficace. Ajoutez une touche de si de la chaîne, tapez/id combo ou autres joyeusetés et le point de l'adresse d'une fonction ou d'une structure. Une super version naïve de la réflexion peut être une collection d'suivantes:
Avec un grand ol' interrupteur cas où vous faites un gestionnaire pour chaque type ou le nom de la ou des macros pour faire fixer le même. Sinon toujours attacher les fonctions qui sont des récepteurs de tout ce qui est dans votre reflectable struct, qui sont les mêmes que pour les gestionnaires, mais avec plus d'une expédition modèle directement sur votre récipient.
Les analyseurs et les Symboles de Débogage sont de bonnes idées. Cependant, la chasse aux sorcières est que C n'a pas vraiment d'avoir des tableaux. Juste des pointeurs vers des trucs.
Par exemple, il n'existe aucun moyen en lisant le code source pour savoir si un char * points à un personnage, une chaîne ou un tableau fixe d'octets selon une certaine "proximité" champ de longueur. C'est un problème pour les lecteurs humains et encore moins de tout outil automatisé.
Pourquoi ne pas utiliser un langage moderne, comme le Java ou le .Net? Peut être plus rapide que C aussi bien.