获取C结构成员列表

是否可以将结构成员列表作为char **

例如,像这样:

 struct mystruct { int x; float y; char *z; }; /* ... */ char **members = MAGIC(struct mystruct); /* {"x", "y", "z", NULL}. */ 

我也对编译器相关的方法感兴趣。 有这样的事吗?

感谢您的时间。

绝对没有标准的方法。

如果您愿意两次编译代码,则可以为第二次传递启用预处理程序定义包装的代码路径,该代码路径从第一次传递生成的编译单元读取调试信息以获取成员名称。 您还可以分析源代码以在运行时获取列表。

最后,您可以使用预处理器宏来定义结构,并让宏在每个结构成员的另一个变量中发出一个条目,从而有效地保持两个不直接相关的项同步。

这是一个概念certificate:

 #include  #include  #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; } 

这是它的输出:

 [int] [x] [void*] [z[2]] [char] [(*f)(char,char)] [char] [y] 

您可以对其进行改进,以更好地支持更复杂的成员类型,并实际构建成员名称列表。

这样做没有便携式标准方式。 上次我想解决类似的问题时,我使用SWIG生成一些XML,然后我处理它以生成我想要的元信息。 gcc-xml也可以做同样的事情。

不,那是不可能的。

C是一种没有reflection的静态类型语言。 类型名称在编译阶段之后没有任何意义,甚至在二进制代码中任何特定变量都不可见的情况也是如此。 只要程序的行为符合语言标准,编译器就可以自由地进行优化和重新排序。

您可以尝试一些预处理器魔术来获得类型名称的有限处理,但这远非一般反映(严格来说,在C语言之外)。

你在C中不能做的主要是:

 const char * tn = "int"; auto n = get_type(tn)(42); // aka "int n = 42;", NOT POSSIBLE 

类型名称不是运行时概念; 除此之外,静态打字使任何这样的结构都不可能。

这是我能想到的为数不多的预处理器噱头之一:

 #define print_size(t) printf("sizeof(" #t ") = %u\n", sizeof(t)); print_size(int); print_size(long double); 

看看Metaresc库https://github.com/alexanderchuranov/Metaresc

它为类型声明提供了接口,该接口也将为该类型生成元数据。 基于元数据,您可以轻松地序列化/反序列化任何复杂的对象。 开箱即用,您可以序列化/反序列化XML,JSON,XDR,类似Lisp的表示法,C-init表示法。

这是一个简单的例子:

 #include  #include  #include "metaresc.h" TYPEDEF_STRUCT (sample_t, int x, float y, string_t z ); int main (int argc, char * argv[]) { mr_td_t * tdp = mr_get_td_by_name ("sample_t"); if (tdp) { int i; for (i = 0; i < tdp->fields_size / sizeof (tdp->fields[0]); ++i) printf ("offset [%zd] size %zd field '%s'\n", tdp->fields[i].fdp->offset, tdp->fields[i].fdp->size, tdp->fields[i].fdp->name.str, tdp->fields[i].fdp->type); } return (EXIT_SUCCESS); } 

该程序将输出

 $ ./struct offset [0] size 4 field 'x' type 'int' offset [4] size 4 field 'y' type 'float' offset [8] size 8 field 'z' type 'string_t' 

图书馆适用于最新的gcc和clang。

Qt扫描.h文件并使用返回此类代码的函数生成.cpp。

您也可以使用一堆宏来实现这一点,但是您需要为每种类型手动编写它们