2010-02-12 40 views
7

मैंने सिस्टम के सी टाइम.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() और स्थानीयसमय(), काफी सरल कर रहे हैं वे सिर्फ संख्या ले, लेकिन mktime() एक टीएम struct लेता है। मैंने एक जेएसओएन हैश में एक टीएम संरचना को चालू करने के लिए एक कस्टम फ़ंक्शन लिखा था।

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

क्या किसी भी दिए गए ढांचे के लिए इसे सामान्य रूप से करने का कोई तरीका है?

नोट: सी, सी ++ नहीं।

उत्तर

4

कम से कम सामान्य रूप से सी में नहीं। लेकिन यदि सी मॉड्यूल डीबग प्रतीकों के साथ संकलित है, और ऑब्जेक्ट मॉड्यूल उपलब्ध है, तो आप इसे पार्स कर सकते हैं और संरचना के बारे में सबकुछ खोज सकते हैं। मैं शर्त लगाता हूं कि आपके सिस्टम के लिए इसकी सहायता करने के लिए एक लाइब्रेरी है।

+0

+1 के साथ हाथ से टीएम संपत्ति निकालें। –

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 के लिए) निर्धारित कर सकते हैं के रूप में की जरूरत है।

फिर से, यह एक सामान्य समाधान नहीं है, लेकिन कम से कम यह आपको थोड़ा करीब ले जाता है, शायद।

+0

धन्यवाद, यह काम करने के लिए थोड़ा और सुखद है। – Schwern

+0

अच्छा, मुझे खुशी है कि यह सहायक है। इसके अलावा, मैंने अभी देखा है कि मैक्रो के विस्तार में मुझे "buf" के आसपास कोष्ठक होना चाहिए था। मैंने उन्हें जोड़ने के लिए अपना जवाब संपादित कर लिया है। – lindes

0

टॉम क्रिस्सेन ने एक बार पस्ट्रक्ट/एच 2 एफ लिखा जो कि पर्ल कोर में है। इस्तेमाल किए गए कंपाइलर से स्टैब्स जानकारी, और सभी डेटा संरचनाओं के लिए पठनीय जानकारी बनाएं।

जेएसओएन में सी structs h2ph पर आधारित छोटा है। http://perl5.git.perl.org/perl.git/blob/HEAD:/utils/h2ph.PL

+0

धन्यवाद, लेकिन क्या यह पर्ल के साथ सी स्ट्रक्चर को पार्स कर रहा है? – Schwern

+0

केवल सीआर स्ट्रक्चर को पर्ल के साथ पार्स करना लगभग असंभव है, केवल तभी जब आप पर्ल में कंपाइलर के कुछ हिस्सों को फिर से लिखते हैं। और इसकी आवश्यकता नहीं है, क्योंकि आपका कंपाइलर इस बहुत ही कंपाइलर के लिए structs के लिए प्रतीकात्मक जानकारी बनाने में सक्षम हो सकता है: stabs, dwarf, xml। एक्सएमएल के लिए जीसीसी :: ट्रांसलेशन यूनिट है, और कनवर्ट :: बाइनरी :: सी भी है जो ucpp का उपयोग करता है। – rurban

0

यह मैक्रो ठीक वही नहीं करता जो आप चाहते हैं (सी डेटा के जेएसओएन डंप जेनरेट करें), लेकिन मुझे लगता है कि यह कुछ संभावना दिखाता है। आप किसी भी सी डेटा की सामग्री को "पी (...) के साथ डंप कर सकते हैं;" कहते हैं।

मैंने इस काम को करने के लिए बाहरी सहायक के रूप में जीडीबी का उपयोग किया, लेकिन libbfd के साथ एक को कार्यान्वित करना संभव है। उस स्थिति में, आप अपने आउटपुट को पूरी तरह से नियंत्रित कर सकते हैं - जैसे जेएसओएन संगत आउटपुट उत्पन्न करना।

#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

+0

उत्तर के लिए धन्यवाद। गैर-मानक पुस्तकालयों पर निर्भर करते हुए, और विशेष रूप से बाह्य कार्यक्रम नहीं, मेरे मामले में संभव नहीं है। हालांकि मुझे यह देखने में दिलचस्पी होगी कि libbfd संस्करण कैसा दिखता है। – Schwern

2

एक ही समस्या का सामना करते हुए, मैं एक अपने आप को लिखा था। https://github.com/jamie-pate/jstruct। यह मौजूदा सी संरचनाओं को एनोटेट करने की अनुमति देने के लिए लिखा गया है, फिर एनोटेशन के आधार पर मेटा-डेटा जानकारी उत्पन्न करता है। लाइब्रेरी जेसन स्ट्रिंग्स और बैक को आयात/निर्यात सी संरचनाओं के लिए मेटाडेटा पढ़ती है। एक पायथन लिपि एनोटेटेड हेडर को पार्स करने और नए शीर्षलेख और मेटाडाटा प्रारंभकर्ताओं को उत्पन्न करने का ख्याल रखती है। Jstruct पुस्तकालय आंतरिक रूप से https://github.com/json-c/json-c का उपयोग करता है। मैंने https://github.com/marel-keytech भी देखा है ... लेकिन यह पूरी चीज लिखने के बाद था। (और उस प्रोजेक्ट के पेज पर जानकारी स्पैस है)

मौजूदा सिस्टम lib से एक ही संरचना को एनोटेट करने के लिए अभी तक कोई समर्थन नहीं है लेकिन आप एक एनोटेटेड कस्टम स्ट्रक्चर में tm संरचना को लपेट सकते हैं। (मुझे लगता है?)

विशेषताएं अनुरोध जोड़ने या यहां तक ​​कि अनुरोधों को खींचने के लिए स्वतंत्र महसूस करें यदि आपके पास ऐसे विचार हैं जो लाइब्रेरी को आपके लिए अधिक उपयोगी बनाते हैं। एक विचार मैं उस तरह का एक @inline टिप्पणी के साथ व्याख्या किए गए आवरण के अंदर केवल struct पढ़ एम्बेड करने के लिए एक तरह से जोड़ने के लिए किया जाएगा था: जैसे (वर्तमान में असमर्थित लेकिन जोड़ा जा सकता है)

//@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"))

संबंधित मुद्दे