Is there a way to reset the C structure?

I wrote a program to explore the limits of the C time.h system function and upload them to JSON. Then other things that depend on these functions may know their limits.

# 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 () and localtime () are quite simple, they just accept numbers, but mktime () accepts a tm structure. I wrote a custom function to turn a tm structure into a JSON hash code.

 /* 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; } 

Is there a way to do this in the general case for any given structure?

Note: C, not C ++.

+7
json c struct
source share
5 answers

Not in C - at least in general. But if the C module is compiled with debugging symbols, and the object module is available, you can parse it and discover everything about the structure. I bet the library for your system will help you there.

+4
source share

Going on the same issue, I wrote it myself. https://github.com/jamie-pate/jstruct . It is written to annotate existing c-structures and then generate metadata based on annotations. The library reads metadata for import / export of c-structures into json strings and vice versa. The Python script takes care of parsing the annotated header and generating new headers and metadata initializers. The jstruct library uses https://github.com/json-c/json-c internally. I also noticed https://github.com/marel-keytech ... but that was after writing everything. (and the information on this page of the project is sparse)

There is no support for annotating one structure from an existing lib system library, but you can wrap the tm structure in an annotated custom structure. (I think?)

Feel free to add feature requests or even pull requests if you have ideas that will make the library more useful to you. One of my ideas would be to add a way to embed such a read-only structure in an annotated wrapper with @inline annotation: for example (not currently supported, but can be added)

 //@json struct my_time { //@inline struct tm tm; } 

the code:

 struct my_time t; mktime(&t.tm); struct json_object *result = jstruct_export(t, my_time); 

At the same time, you can do the same thing without @inline (since it hasn't been written yet) and just json_object_to_json_string(json_object_object_get(result, "tm")) tm property manually using json_object_to_json_string(json_object_object_get(result, "tm"))

+2
source share

This will not give you what you are asking for, but it may help a little:

 #define NAME_AND_INT(buf, obj, param) \ sprintf((buf), "\"%s\": %d, ", #param, (obj)->(param)) 

Then you can iterate, for example. something like (note: not verified; consider this pseudocode):

 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 just * been allocated in a different way. At least that 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'; /* ... */ } 

Similarly, you can define NAME_AND_STRING , NAME_AND_LONG , etc. (for tm_zone and tm_gmtoff) as needed.

Again, this is not a general solution, but at least you are a little closer, maybe.

+1
source share

Tom Christiansen wrote pstruct / h2ph, which is located in perl CORE to parse .stabs information from the compiler used and create readable information for all data structures.

C structures in JSON are trivial based on h2ph. http://perl5.git.perl.org/perl.git/blob/HEAD:/utils/h2ph.PL

0
source share

This macro does not exactly do what you want (generate a JSON dump of C data), but I think it shows some possibility. You can flush the contents of any C data with "p (...);" call.

I used gdb as an external helper to do this work, but you can implement one with libbfd. In this case, you can completely control your output - for example, generate a JSON-compatible output.

 #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 

Indentation is lost in the upper paste, but you can grab the source from: https://github.com/tai/ruby-p-for-c

0
source share

All Articles