Is it possible to get the list of members of a structure as a char **
?
For example, something like this:
struct mystruct {
int x;
float y;
char *z;
};
/* ... */
char **members = MAGIC(struct mystruct); /* {"x", "y", "z", NULL}. */
I am also interested in compiler-dependent methods. Is there such a thing ?
Thank you for your time.
Here's a proof of concept:
#include <stdio.h>
#include <string.h>
#define MEMBER(TYPE,NAME,MORE) TYPE NAME MORE
#define TSTRUCT(NAME,MEMBERS) \
typedef struct NAME { \
MEMBERS \
} NAME; \
const char* const NAME##_Members = #MEMBERS;
#define PRINT_STRUCT_MEMBERS(NAME) printStructMembers(NAME##_Members)
TSTRUCT(S,
MEMBER(int,x;,
MEMBER(void*,z[2];,
MEMBER(char,(*f)(char,char);,
MEMBER(char,y;,
)))));
void printStructMembers(const char* Members)
{
int level = 0;
int lastLevel = 0;
const char* p;
const char* pLastType = NULL;
const char* pLastTypeEnd = NULL;
for (p = Members; *p; p++)
{
if (strstr(p, "MEMBER(") == p)
{
p += 6; // strlen("MEMBER")
level++;
lastLevel = level;
pLastType = p + 1;
}
else if (*p == '(')
{
level++;
}
else if (*p == ')')
{
level--;
}
else if (*p == ',')
{
if (level == lastLevel)
{
if ((pLastType != NULL) && (pLastTypeEnd == NULL))
{
pLastTypeEnd = p;
}
}
}
else if (strstr(p, ";,") == p)
{
if ((pLastType != NULL) && (pLastTypeEnd != NULL))
{
const char* pp;
printf("[");
for (pp = pLastType; pp < pLastTypeEnd; pp++)
printf("%c", *pp); // print type
printf("] [");
for (pp = pLastTypeEnd + 1; pp < p; pp++)
printf("%c", *pp); // print name
printf("]\n");
}
pLastType = pLastTypeEnd = NULL;
}
}
}
char fadd(char a, char b)
{
return a + b;
}
S s =
{
1,
{ NULL, NULL },
&fadd,
'a'
};
int main(void)
{
PRINT_STRUCT_MEMBERS(S);
return 0;
}
This is it's output:
[int] [x]
[void*] [z[2]]
[char] [(*f)(char,char)]
[char] [y]
You can improve it to better support more complex member types and to actually build a list of names of the members.
There's definitely no standard way.
If you're willing to compile the code twice, you could have a preprocessor-define-wrapped codepath only enabled for the second pass which reads debugging information from the compilation units produced by the first pass to get the member names. You could also analyze the source code to get the list at run time.
Finally, you could use preprocessor macros to define the struct and have the macros also emit an entry in another variable for each struct member, effectively keeping two not-directly-related items in sync.
There's no portable standard way of doing this. Last time I wanted to solve a similar problem I used SWIG to produce some XML which I then processed to generate the meta information I wanted. gcc-xml could do the same thing too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With