how come #include "*.cpp" works?

mwoehlke mwoehlke@tibco.com
Wed May 24 16:03:00 GMT 2006


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



More information about the Cygwin-talk mailing list