This is the mail archive of the cygwin-talk mailing list for the cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: how come #include "*.cpp" works?


mwoehlke wrote:
I'm writing a program to dump structures from core dumps generated from symbol-less binaries (i.e. no easy looking at structures, etc, in gdb). It works great; you give it a structure name and an address and it reads, decodes, and prints the structure, as well as referenced objects like strings (the idea being to dump whole hierarchies of structures at once).

Anyway... what I do is have an "OBJ" ABC and subclass it for each type of structure I want this program to be able to understand. What I want to do is have some system that entails the fewest *lines* of code (macros to turn one line into lots of *actual* code are OK) that can a: construct an object by name, and b: provide me a list of names of classes which can be created (i.e. if you enter an invalid one, it will tell you valid ones). Any thoughts? (Maybe dropping a hippo on the code will make it as small as I want it to be? ;-))

Below is what I ultimately wound up using. Thanks again to Dave Korn for the assistance in coming up with this solution!


The final requirements for this solution are:
1: An updated list of class headers in Makefile.
2: Classes must be declared with 'CREATABLE_CLASS(name)' instead of 'class name : virtual public OBJECT'.
3: A create_<name> function must be written. If all objects were constructed the same, this could have been lumped into the declaration CREATABLE_CLASS macro, however not all constructors take the same arguments, which is why 'create_<name>' takes an argc/argv pair. IOW this requirement cannot be eliminated.


The list-in-code (including pointers to create functions) is maintained via (1), which is the only "overhead" other than (3) and the actual class declaration... and if I really wanted to, I could get rid of this as well (but to be worth it, I would want/need a way to determine what files are actually used to build the executable, and I think this is one case where I /prefer/ to update the list by hand).

Thus, except for Makefile, it achieves the objective of having a list which is entirely generated and does not need to be maintained by hand.


=== For declaring an object #define CREATABLE_CLASS(name) \ extern class OBJECT* create_##name( int argc, const char* argv[] ); \ class name : virtual public OBJECT

=== Example declaration
CREATABLE_CLASS( STRING )
{
    public:
        STRING( long ptr, long lim = MAX_STR );
        virtual ~STRING();
        ...

    protected:
        char* _data;
};

=== For creating object.def (in Makefile)
objects.def : $(classes)
	cat $(classes) | grep CREATABLE_CLASS > $@

(This requires '$(classes)' to be kept up to date, but that's OK because '$(classes)' becomes part of '$(objects)', which defines the prerequisites for the executable - i.e. this isn't really adding any work, although I suppose I could go one step further and generate the object prerequisites as well; this would certainly be do-able)


=== So main.cpp doesn't need the headers for every class #undef CREATABLE_CLASS #define CREATABLE_CLASS(name) \ extern class T_OBJ* create_##name( int argc, const char* argv[] ); #include "objects.def"

=== And finally for the list
#undef CREATABLE_CLASS
#define CREATABLE_CLASS(name) { #name, create_##name },

typedef OBJECT *(*OBJ_CREATOR)( int argc, const char* argv[] );
typedef struct {
    const char* name;
    OBJ_CREATOR create;
} OBJECT_LIST_ENTRY;

OBJECT_LIST_ENTRY createable_object[] = {
#include "objects.def"
{ NULL, NULL }
};

(The last '{ NULL, NULL }' entry is needed to have something after the comma that the macro generates.)

--
Matthew
Doom doom dooM doo-DooM dOOm DOom doOM... DOOM! -- Gir


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]