我编写了一个程序来探测系统的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 ++。
答案 0 :(得分:4)
不在C-至少一般。但是如果使用调试符号编译C模块,并且对象模块可用,则可以解析该模块并发现有关结构的所有内容。我打赌你的系统有一个库可以帮助你。
答案 1 :(得分:2)
遇到同样的问题,我自己写了一个。 https://github.com/jamie-pate/jstruct。编写它是为了允许注释现有的c结构,然后根据注释生成元数据信息。该库读取元数据以将c结构导入/导出到json字符串并返回。 python脚本负责解析带注释的头并生成新的头和元数据初始化器。 jstruct库在内部使用https://github.com/json-c/json-c。 我也注意到https://github.com/marel-keytech ......但那是在写完整件事之后。 (该项目页面的信息很稀疏)
现在还没有从现有系统库中注释单个结构的支持,但是您可以将tm
结构包装在带注释的自定义结构中。 (我想?)
如果您有想法使图书馆对您更有用,请随意添加功能请求甚至提取请求。我有一个想法是添加一种方法,在带有@inline
注释的带注释的包装器中嵌入那种只读结构:例如(目前不支持但可以添加)
//@json
struct my_time {
//@inline
struct tm tm;
}
代码:
struct my_time t;
mktime(&t.tm);
struct json_object *result = jstruct_export(t, my_time);
同时你可以在没有@inline
的情况下做同样的事情(因为它还没有编写),只需用json_object_to_json_string(json_object_object_get(result, "tm"))
手动提取tm属性
答案 2 :(得分:1)
这并不能完全满足您的要求,但它可能会有所帮助:
#define NAME_AND_INT(buf, obj, param) \
sprintf((buf), "\"%s\": %d, ", #param, (obj)->(param))
然后你可以迭代,例如类似的东西(注意:没有经过测试;考虑这个伪代码):
char * tm_as_json(const struct tm* date) {
/* ... */
char buf[BUFSIZ]; /* or, use your date_json */
pos = buf; /* I note you use the equivalent of &buf -- that works too */
/* (not sure which is "better", but I've always left the & off
* things like that -- buf is essentially a pointer, it's just
* been allocated in a different way. At least that's how I
* think of it. */
pos += NAME_AND_INT(pos, date, tm_sec);
pos += NAME_AND_INT(pos, date, tm_min);
/* ... more like this ... */
/* strip trailing ", " (comma-space): */
pos-=2;
*pos = '\0';
/* ... */
}
您可以根据需要同样定义NAME_AND_STRING
,NAME_AND_LONG
等(对于tm_zone和tm_gmtoff)。
同样,它不是一般的解决方案,但它至少可以让你更接近,也许。
答案 3 :(得分:1)
免责声明:我是项目https://github.com/tamask1s/zax-parser
的所有者在库的帮助下,如果您提供了有关结构成员的一些需要转换的信息,则可以将C结构转换为JSON。无需在项目中包含生成的代码,但需要使用c ++ 11编译器才能使用它。
该库还很不成熟,因为我仅实现了所需的功能,但您可以扩展它,也可以将其用作灵感。
示例:
#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;
--- some_json的值:---
{"x":9, "s":"something"}
也可以嵌套对象,请检查以下示例:https://tamask1s.github.io/zax-parser/index.html#Parsing_of_structures_with_fields_of_serializable_structures
答案 4 :(得分:0)
基于h2ph,C结构到JSON是微不足道的。 http://perl5.git.perl.org/perl.git/blob/HEAD:/utils/h2ph.PL
答案 5 :(得分:0)
这个宏并没有完全符合你的要求(生成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
上面的粘贴会导致缩进,但您可以从https://github.com/tai/ruby-p-for-c
获取来源