Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有没有办法转储C结构?_C_Json_Struct - Fatal编程技术网

有没有办法转储C结构?

有没有办法转储C结构?,c,json,struct,C,Json,Struct,我编写了一个程序来探测系统的C time.h函数的限制,并将它们转储到JSON中。然后依赖于这些函数的其他事物可以知道它们的极限 # system time.h limits, as JSON { "gmtime": { "max": 2147483647, "min": -2147483648 }, "localtime": { "max": 2147483647, "min": -2147483648 }, "mktime": {

我编写了一个程序来探测系统的C time.h函数的限制,并将它们转储到JSON中。然后依赖于这些函数的其他事物可以知道它们的极限

# system time.h limits, as JSON 
{
  "gmtime": {
    "max": 2147483647,
    "min": -2147483648
  },
  "localtime": {
    "max": 2147483647,
    "min": -2147483648
  },
  "mktime": {
    "max": {
      "tm_sec": 7,
      "tm_min": 14,
      "tm_hour": 19,
      "tm_mday": 18,
      "tm_mon": 0,
      "tm_year": 138,
      "tm_wday": 1,
      "tm_yday": 17,
      "tm_isdst": 0
    },
    "min": {
      "tm_sec": 52,
      "tm_min": 45,
      "tm_hour": 12,
      "tm_mday": 13,
      "tm_mon": 11,
      "tm_year": 1,
      "tm_wday": 5,
      "tm_yday": 346,
      "tm_isdst": 0
    }
  }
}
gmtime()和localtime()非常简单,它们只需要数字,但mktime()需要一个tm结构。我编写了一个自定义函数,将tm结构转换为JSON哈希

/* Dump a tm struct as a json fragment */
char * tm_as_json(const struct tm* date) {
    char *date_json = malloc(sizeof(char) * 512);
#ifdef HAS_TM_TM_ZONE
    char zone_json[32];
#endif
#ifdef HAS_TM_TM_GMTOFF
    char gmtoff_json[32];
#endif

    sprintf(date_json,
            "\"tm_sec\": %d, \"tm_min\": %d, \"tm_hour\": %d, \"tm_mday\": %d, \"tm_mon\": %d, \"tm_year\": %d, \"tm_wday\": %d, \"tm_yday\": %d, \"tm_isdst\": %d",
            date->tm_sec, date->tm_min, date->tm_hour, date->tm_mday,
            date->tm_mon, date->tm_year, date->tm_wday, date->tm_yday, date->tm_isdst
    );

#ifdef HAS_TM_TM_ZONE
    sprintf(&zone_json, ", \"tm_zone\": %s", date->tm_zone);
    strcat(date_json, zone_json);
#endif
#ifdef HAS_TM_TM_GMTOFF
    sprintf(&gmtoff_json", \"tm_gmtoff\": %ld", date->tm_gmtoff);
    strcat(date_json, gmtoff_json);
#endif

    return date_json;
}
对于任何给定的结构,有没有一种通用的方法可以做到这一点


<>注释:C,不是C++。

一般不在C中。但是如果C模块是用调试符号编译的,并且对象模块是可用的,那么您可以解析它并发现关于该结构的所有信息。我打赌您的系统有一个库可以帮助您实现这一点。

这并不能完全满足您的要求,但它可能会有所帮助:

#define NAME_AND_INT(buf, obj, param) \
        sprintf((buf), "\"%s\": %d, ", #param, (obj)->(param))
<>你可以迭代,例如(注意:未测试;考虑这个伪代码):

您可以根据需要类似地定义
NAME\u和\u STRING
NAME\u和\u LONG
等(用于tm\u区域和tm\u gmtoff)


再说一次,它不是一个通用的解决方案,但它至少可以让您更接近它。

Tom Christiansen曾经编写了perl CORE中的pstruct/h2ph来解析。stab从使用的编译器中获取信息,并为所有数据结构创建可读信息

基于h2ph,将C结构转换成JSON非常简单。

这个宏并不完全符合您的要求(生成C数据的JSON转储),但我认为它显示了某种可能性。您可以通过“p(…);”调用转储任何C数据的内容

我使用gdb作为外部助手来完成这项工作,但是可以使用libbfd实现一个。在这种情况下,您可以完全控制输出,就像生成JSON兼容的输出一样

#ifndef PP_H
#define PP_H
/*
* Helper function (macro) for people who loves printf-debugging.
* This dumps content of any C data/structure/expression without prior
* knowledge of actual format. Works just like "p" or "pp" in Ruby.
*
* Usage:
* p(anyexpr);
*
* NOTE:
* - Program should be compiled with "-g" and preferrably, with "-O0".
*
* FIXME:
* - Would be better if this doesn't depend on external debugger to run.
* - Needs improvement on a way prevent variable from being optimized away.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>

// Counts number of actual arguments.
#define COUNT_(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define COUNT(...) COUNT_(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)

// Dispatches macro call by number of actual arguments.
// Following is an example of actual macro expansion performed in case
// of 3 arguments:
//
// p(a, b, c)
// -> FUNC_N(p, COUNT(a, b, c), a, b, c)
// -> FUNC_N(p, 3, a, b, c)
// -> p_3(a, b, c)
//
// This means calling with simple "p(...)" is fine for any number of
// arguments, simulating "true" variadic macro.
#define CONCAT(name, count) name##count
#define FUNC_N(name, count, ...) CONCAT(name, count)(__VA_ARGS__)

// Forbids variable from being optimized out, so debugger can access it.
//
// FIXME:
// - Current implementation does not work with certain type of symbols
#define ENSURE(...) FUNC_N(ENSURE_, COUNT(__VA_ARGS__), __VA_ARGS__)
#define ENSURE_1(a) asm(""::"m"(a))
#define ENSURE_2(a, ...) do { ENSURE_1(a); ENSURE_1(__VA_ARGS__); } while (0)
#define ENSURE_3(a, ...) do { ENSURE_1(a); ENSURE_2(__VA_ARGS__); } while (0)
#define ENSURE_4(a, ...) do { ENSURE_1(a); ENSURE_3(__VA_ARGS__); } while (0)
#define ENSURE_5(a, ...) do { ENSURE_1(a); ENSURE_4(__VA_ARGS__); } while (0)
#define ENSURE_6(a, ...) do { ENSURE_1(a); ENSURE_5(__VA_ARGS__); } while (0)
#define ENSURE_7(a, ...) do { ENSURE_1(a); ENSURE_6(__VA_ARGS__); } while (0)
#define ENSURE_8(a, ...) do { ENSURE_1(a); ENSURE_7(__VA_ARGS__); } while (0)

// Dumps content of given symbol (uses external GDB for now)
//
// NOTE:
// - Should use libbfd instead of gdb? (but this adds complexity...)
#define PP_D(...) do { \
char *arg[] = { __VA_ARGS__, NULL }; \
char **argp = arg; \
char cmd[1024]; \
FILE *tmp = tmpfile(); \
fprintf(tmp, "attach %d\n", getpid()); \
fprintf(tmp, "frame 2\n"); \
while (*argp) \
fprintf(tmp, "p %s\n", *argp++); \
fprintf(tmp, "detach\n"); \
fflush(tmp); \
sprintf(cmd, "gdb -batch -x /proc/%d/fd/%d", \
getpid(), fileno(tmp)); \
system(cmd); \
fclose(tmp); \
} while (0)

#define PP(...) do { \
FUNC_N(PP_, COUNT(__VA_ARGS__), __VA_ARGS__); \
ENSURE(__VA_ARGS__); \
} while (0)
#define PP_1(a) do { PP_D(#a); } while (0)
#define PP_2(a,b) do { PP_D(#a,#b); } while (0)
#define PP_3(a,b,c) do { PP_D(#a,#b,#c); } while (0)
#define PP_4(a,b,c,d) do { PP_D(#a,#b,#c,#d); } while (0)
#define PP_5(a,b,c,d,e) do { PP_D(#a,#b,#c,#d,#e); } while (0)
#define PP_6(a,b,c,d,e,f) do { PP_D(#a,#b,#c,#d,#e,#f); } while (0)
#define PP_7(a,b,c,d,e,f,g) do { PP_D(#a,#b,#c,#d,#e,#f,#g); } while (0)
#define PP_8(a,b,c,d,e,f,g,h) do { PP_D(#a,#b,#c,#d,#e,#f,#g,#h); } while (0)

// Comment this out if you think this is too aggressive.
#define p PP

#endif
#ifndef PP#H
#定义PP_H
/*
*帮助函数(宏)为喜欢printf调试的人提供。
*这会转储任何C数据/结构/表达式的内容,而无需事先
*了解实际格式。就像Ruby中的“p”或“pp”一样工作。
*
*用法:
*p(anyexpr);
*
*注:
*-程序应使用“-g”编译,最好使用“-O0”编译。
*
*修理工:
*-如果不依赖外部调试器运行,则效果更好。
*-需要改进防止变量优化的方法。
*/
#包括
#包括
#包括
#包括
//计算实际参数的数量。
#定义计数(_1,_2,_3,_4,_5,_6,_7,_8,N,…)N
#定义计数(…)计数(uuu VA_参数_uuu,8,7,6,5,4,3,2,1)
//按实际参数数分派宏调用。
//以下是在以下情况下执行的实际宏扩展示例:
//共有3个论点:
//
//p(a、b、c)
//->函数N(p,计数(a,b,c),a,b,c)
//->函数N(p,3,a,b,c)
//->p_3(a、b、c)
//
//这意味着使用简单的“p(…)”进行调用对于任何数量的
//参数,模拟“真”变量宏。
#定义CONCAT(名称,计数)名称##计数
#定义函数(名称,计数,…)CONCAT(名称,计数)(\uuu VA\u参数)
//禁止优化变量,以便调试器可以访问它。
//
//修理工:
//-当前实施不适用于某些类型的符号
#定义确保(…)函数(确保,计数(uuu VA_ARGS_uuu),uu VA_ARGS_uu)
#定义确保1(a)asm(“:“m”(a))
#定义sure_2(a,…)do{sure_1(a);sure_1(uu VA_ARGS_uu);}while(0)
#定义sure_3(a,…)do{sure_1(a);sure_2(uu VA_ARGS_uu)}while(0)
#定义sure_4(a,…)do{sure_1(a);sure_3(uu VA_ARGS_uu)}while(0)
#定义sure_5(a,…)do{sure_1(a);sure_4(uu VA_ARGS_uu)}while(0)
#定义sure_6(a,…)do{sure_1(a);sure_5(uu VA_ARGS_uu)}while(0)
#定义sure_7(a,…)do{sure_1(a);sure_6(uu VA_ARGS_uu)}while(0)
#定义sure_8(a,…)do{sure_1(a);sure_7(uu VA_ARGS_uu)}while(0)
//转储给定符号的内容(目前使用外部GDB)
//
//注:
//-是否应该使用libbfd而不是gdb?(但这增加了复杂性…)
#定义PP_D(…)do{\
char*arg[]={{uu_VA_ARGS,NULL}\
字符**argp=arg\
char cmd[1024]\
文件*tmp=tmpfile()\
fprintf(tmp,“附加%d\n”,getpid())\
fprintf(tmp,“帧2\n”)\
while(*argp)\
fprintf(tmp,“p%s\n”,*argp++)\
fprintf(tmp,“分离\n”)\
fflush(tmp)\
sprintf(cmd,“gdb-batch-x/proc/%d/fd/%d”\
getpid(),fileno(tmp))\
系统(cmd)\
fclose(tmp)\
}而(0)
#定义PP(…)do{\
FUNC_N(PP_,COUNT(__VA_ARGS_____)和u VA_ARGS___)\
确保(_VA_ARGS__;)\
}而(0)
#定义PP_1(a)do{PP_D(#a);}while(0)
#定义PP_2(a,b)do{PP_D(#a,b)}while(0)
#定义PP_3(a,b,c)do{PP_D(#a,b,c)}while(0)
#定义PP_4(a,b,c,d)do{PP_d(#a,b,c,d)}while(0)
#定义PP#5(a,b,c,d,e)do{PP#d(#a,#b,#c,#d,#e)}而(0)
#定义PP#6(a,b,c,d,e,f)do{PP#d(#a,#b,#c,#d,#e,#f)}while(0)
#定义PP#7(a,b,c,d,e,f,g)do{PP#d(#a,#b,#c,#d,#e,#f,#g)}while(0)
#定义PP#8(a,b,c,d,e,f,g,h)do{PP#d(#a,#b,#c,#d,#e,#f,#g,#h)}while(0)
//如果你认为这太过激进,请对此进行评论。
#定义p-PP
#恩迪夫

缩进在上面的粘贴中丢失了,但您可以从以下位置获取来源:

遇到同样的问题,我自己写了一个。它允许注释现有的c结构,然后根据注释生成元数据信息。库读取元数据以将c结构导入/导出为json字符串并返回。python脚本负责解析带注释的头并生成新的头和元数据初始值设定项。jstruct库在内部使用。 我也注意到。。。但那是在写完整件事之后。(该项目页面上的信息很少)

目前还不支持从现有系统库中注释单个结构,但您可以将
tm
结构包装到带注释的自定义结构中。(我想是吧?)

如果您有让库对您更有用的想法,可以随意添加功能请求,甚至拉取请求。我的一个想法是添加一种方法,将这种只读结构嵌入带有
@inline
#ifndef PP_H
#define PP_H
/*
* Helper function (macro) for people who loves printf-debugging.
* This dumps content of any C data/structure/expression without prior
* knowledge of actual format. Works just like "p" or "pp" in Ruby.
*
* Usage:
* p(anyexpr);
*
* NOTE:
* - Program should be compiled with "-g" and preferrably, with "-O0".
*
* FIXME:
* - Would be better if this doesn't depend on external debugger to run.
* - Needs improvement on a way prevent variable from being optimized away.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>

// Counts number of actual arguments.
#define COUNT_(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N
#define COUNT(...) COUNT_(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)

// Dispatches macro call by number of actual arguments.
// Following is an example of actual macro expansion performed in case
// of 3 arguments:
//
// p(a, b, c)
// -> FUNC_N(p, COUNT(a, b, c), a, b, c)
// -> FUNC_N(p, 3, a, b, c)
// -> p_3(a, b, c)
//
// This means calling with simple "p(...)" is fine for any number of
// arguments, simulating "true" variadic macro.
#define CONCAT(name, count) name##count
#define FUNC_N(name, count, ...) CONCAT(name, count)(__VA_ARGS__)

// Forbids variable from being optimized out, so debugger can access it.
//
// FIXME:
// - Current implementation does not work with certain type of symbols
#define ENSURE(...) FUNC_N(ENSURE_, COUNT(__VA_ARGS__), __VA_ARGS__)
#define ENSURE_1(a) asm(""::"m"(a))
#define ENSURE_2(a, ...) do { ENSURE_1(a); ENSURE_1(__VA_ARGS__); } while (0)
#define ENSURE_3(a, ...) do { ENSURE_1(a); ENSURE_2(__VA_ARGS__); } while (0)
#define ENSURE_4(a, ...) do { ENSURE_1(a); ENSURE_3(__VA_ARGS__); } while (0)
#define ENSURE_5(a, ...) do { ENSURE_1(a); ENSURE_4(__VA_ARGS__); } while (0)
#define ENSURE_6(a, ...) do { ENSURE_1(a); ENSURE_5(__VA_ARGS__); } while (0)
#define ENSURE_7(a, ...) do { ENSURE_1(a); ENSURE_6(__VA_ARGS__); } while (0)
#define ENSURE_8(a, ...) do { ENSURE_1(a); ENSURE_7(__VA_ARGS__); } while (0)

// Dumps content of given symbol (uses external GDB for now)
//
// NOTE:
// - Should use libbfd instead of gdb? (but this adds complexity...)
#define PP_D(...) do { \
char *arg[] = { __VA_ARGS__, NULL }; \
char **argp = arg; \
char cmd[1024]; \
FILE *tmp = tmpfile(); \
fprintf(tmp, "attach %d\n", getpid()); \
fprintf(tmp, "frame 2\n"); \
while (*argp) \
fprintf(tmp, "p %s\n", *argp++); \
fprintf(tmp, "detach\n"); \
fflush(tmp); \
sprintf(cmd, "gdb -batch -x /proc/%d/fd/%d", \
getpid(), fileno(tmp)); \
system(cmd); \
fclose(tmp); \
} while (0)

#define PP(...) do { \
FUNC_N(PP_, COUNT(__VA_ARGS__), __VA_ARGS__); \
ENSURE(__VA_ARGS__); \
} while (0)
#define PP_1(a) do { PP_D(#a); } while (0)
#define PP_2(a,b) do { PP_D(#a,#b); } while (0)
#define PP_3(a,b,c) do { PP_D(#a,#b,#c); } while (0)
#define PP_4(a,b,c,d) do { PP_D(#a,#b,#c,#d); } while (0)
#define PP_5(a,b,c,d,e) do { PP_D(#a,#b,#c,#d,#e); } while (0)
#define PP_6(a,b,c,d,e,f) do { PP_D(#a,#b,#c,#d,#e,#f); } while (0)
#define PP_7(a,b,c,d,e,f,g) do { PP_D(#a,#b,#c,#d,#e,#f,#g); } while (0)
#define PP_8(a,b,c,d,e,f,g,h) do { PP_D(#a,#b,#c,#d,#e,#f,#g,#h); } while (0)

// Comment this out if you think this is too aggressive.
#define p PP

#endif
//@json
struct my_time {
    //@inline
    struct tm tm;
}
struct my_time t;

mktime(&t.tm);
struct json_object *result = jstruct_export(t, my_time);
#define some_json_properties JSON_PROPERTY(x), JSON_PROPERTY(s) 
 
struct some_class 
{ 
    int x = 9; 
    std::string s = "something";  
 
    ZAX_JSON_SERIALIZABLE(some_class, some_json_properties) 
}; 
 
std::string some_json = some_obj;