"Jérôme de Lagausie" wrote:
Hello,
In one hand, I've got a set of more than 130 different structures,
mostly rather simple (a set of simple data members such as int, long, char
[], float ...)
sample :
[h2.h]
#ifndef _H2_H_
#define _H2_H_
#define MEMBER3_LENGTH 100
struct h2 {
int member1 ;
long member2 ;
char member3[MEMBER3_LENGTH] ;
....
} t_h2 ;
#endif
sometimes more complex :
sample :
[h3.h]
#ifndef _H3_H_
#define _H3_H_
struct h3_part {
int member1 ;
long member2 ;
....
} t_h3_part ;
struct h3 {
int memberx ;
t_h3_part innerstruct[3] ;
...
}
#endif
And I need to display the content of any structure, with a function looking
like something like this proto :
void display_content_of (void * data, const char which_structure[])
{
...
if (strcmp (which_structure, "t_h2") == 0)
{
t_h2 *p_h2 = (t_h2 *)data ;
show_all_members_of_h2 (p_h2) ;
}
...
}
I suppose the solution to my quest is something like what does a compiler do
(indeed, my solution is not supposed to work just at run time... It canuse
include files, process them, to form a new set of files, compile them and
build the tool I need...)
Maybe yacc & lex would be helpfull, but I need some hints 'cause I don't
know them.
Maye be a solution based on "indexof" and macros exists, too, but I'm not
that confident...
One method is to build a description for each struct type,
and pass that instead of the which_structure string. The
description gives the offsetof (not indexof) each element
you want to display, plus information about the element type
and possibly the name and display format. Here's a sketch:
typedef struct {
size_t offset;
enum { INT, LONG, ... } type;
const char *name;
const char *format;
} Element;
const Element h2_layout[] = {
{ offsetof(struct h2, member1), INT, "member1", "%d" },
{ offsetof(struct h2, member2), LONG, "member2", "%lo" },
{ offsetof(struct h3, member3), CHAR_ARRAY, "member3", "%s" },
...
{ 0, 0, NULL, NULL } /* end of description */
};
void display_content_of(const void *data, const Element *field) {
const char *ptr;
for ( ; field->name != NULL; ++field) {
printf ("%s = ", field->name);
ptr = (const char*)data + field->offset;
switch (field->type) {
case INT:
printf (field->format, *(const int*)ptr);
break;
case LONG:
printf (field->format, *(const long*)ptr);
break;
case CHAR_ARRAY:
printf (field->format, ptr);
break;
...
}
putchar ('\n');
}
}
This is more or less what a debugger does, although debuggers
usually rely on "private agreements" with the compiler to obtain
the information here encoded in arrays of Element structures.
Building the Element arrays can be tedious, and errors can
result if somebody adds a new element to an existing structure
but forgets to update the corresponding description. In a large
software project, it's probably best to write a small program that
accepts a simple language describing the desired structs, and use
this program to generate C code declaring each struct and defining
its Element array. If you arrange to run this program before
compilation, the struct definitions and their Element descriptions
will remain in agreement.
--
Er*********@sun.com