2009-10-26 13 views
28

मैं चर से डेटा डंप करने के लिए एक उपकरण विकसित कर रहा हूँ। मुझे परिवर्तनीय नाम, और मानों को डंप करने की आवश्यकता है।सी में चर नाम पाने के लिए प्रोग्रामेटिक तरीका?

मेरा समाधान: एक चर के रूप में स्टोर परिवर्तनीय नाम, और "वैरिएबल नाम" प्रिंट करें, इसके बाद इसके मूल्य।

क्या परिवर्तनीय नाम जानने के लिए कोई प्रोग्रामेटिक तरीका है?

उत्तर

47

आप कुछ इस तरह की कोशिश कर सकते:

#define DUMP(varname) fprintf(stderr, "%s = %x", #varname, varname); 

मैं this header का उपयोग करते थे मैंने लिखा, जब मैं सी के लिए नया था, यह कुछ उपयोगी विचार हो सकता है।

#define TRACE(fmt, var) \ 
     (error_at_line(0, 0, __FILE__, __LINE__, "%s : " fmt, #var, var)) 

आप सी ++ का उपयोग कर रहे हैं, तो आप भेजे गए मान के प्रकार इस्तेमाल कर सकते हैं: उदाहरण के लिए यह आप एक सी मूल्य प्रिंट और एक में फॉर्मेट स्पेसिफायर (और साथ ही कुछ अतिरिक्त जानकारी) प्रदान करने की अनुमति होगी और इसे उचित रूप से आउटपुट करें। यदि यह मामला है तो मैं "सुंदर प्रिंट" वैरिएबल मानों के लिए एक और अधिक आकर्षक उदाहरण प्रदान कर सकता हूं।

+0

कार्यक्रम के अंदर से चीजों को करना एक अच्छा विचार है। स्ट्रिंग स्थिरांक का एक गुच्छा बनाता है, यह निश्चित रूप से है। –

+0

आप इसे 'डंप (वर्नाम, प्रारूप)' के रूप में परिभाषित करने और 'fprintf' में'% s = "प्रारूप" \ n "' के रूप में परिभाषित करने से बेहतर हैं, जिससे इसे अधिक प्रकारों पर काम करने की अनुमति मिलती है: 'DUMP (somestring, "% s") 'या' डंप (कुछ, "% d") '। – caf

+0

सी की गैर-आत्मनिर्भर प्रकृति के आसपास यह सामान्य तरीका है। जैसा कि आप कल्पना कर सकते हैं, इसकी सीमाएं और जाल हैं, लेकिन यह उतना ही अच्छा है जितना आप अपने स्वयं के आत्मनिर्भर दुभाषिया के निर्माण के बिना कर सकते हैं। – dmckee

1

यदि आपका निष्पादन योग्य डिबगिंग जानकारी के साथ संकलित है, तो आप यह जानकारी प्राप्त कर सकते हैं। यदि नहीं, तो आप शायद भाग्य से बाहर हैं। तो आप एक डीबगर बना रहे हैं? क्यूं कर? सी के लिए मौजूदा डिबगर्स बहुत परिपक्व हैं। पहिया को फिर से आविष्कार करने के बजाय मौजूदा उपकरणों का उपयोग क्यों न करें?

+0

कार्यावधि में डिबगर पूछताछ कृपया के कुछ उदाहरण? –

11

सी में, परिवर्तनीय नाम संकलन चरण के दौरान मौजूद हैं (और लिंक चरण, यदि चर वैश्विक है), लेकिन रनटाइम पर उपलब्ध नहीं हैं। आपको एक समाधान चुनना होगा जिसमें परिवर्तनीय नाम को इंगित करने वाली एक शाब्दिक स्ट्रिंग शामिल हो।

1

आपके प्रोग्राम के अंदर से ऐसा करने का कोई अच्छा तरीका नहीं है, मुझे डर है (एनाक्रोलिक्स के उत्तर से अलग)। मुझे लगता है कि आपकी समस्या का सही समाधान एक डीबगर स्क्रिप्ट है। अधिकांश डिबगर्स में, जब भी डीबगर प्रोग्राम निष्पादन (ब्रेकपॉइंट, आप ^C इत्यादि) को दबाते हैं तो आप इसे चलाने के लिए भी इसे हुक कर सकते हैं और हर बार जब आप इसके साथ बातचीत करते हैं तो अपने प्रोग्राम स्टेटस का स्नैपशॉट प्राप्त कर सकते हैं।

4

यदि आपको मनमाने ढंग से चर के लिए ऐसा करने की आवश्यकता है तो आपको शायद एक डीबगर एपीआई का उपयोग करने की आवश्यकता होगी जो संकलक या मंच प्रदान करता है (जैसे विंडोज़ पर डीबीजीएचल्प)।

कुछ एम्बेडेड सिस्टमों पर मैंने काम किया है, हमें कुछ महत्वपूर्ण चर के मानों को कम करने में सक्षम होने की आवश्यकता है जो समय से पहले ज्ञात हैं, और ऐसा करने के लिए जो हमें चाहिए वह एक साधारण नाम/सूचक तालिका है :

typedef 
struct vartab { 
    char const* name; 
    int * var; 
} vartab; 


vartab varTable[] = { 
    { "foo", &foo }, 
    { "bar", &bar } 
}; 

तो मैं बस थोड़ी दिनचर्या है कि प्रश्न में चर नाम के लिए तालिका खोजता है, और नाम उदासीनता का इस्तेमाल किया और डेटा सूचक द्वारा की ओर इशारा किया। यदि आपको सादे स्याही के अलावा डेटा को डंप करने की आवश्यकता है, तो आप एक प्रिंटफ-स्टाइल फॉर्मेटर रखने के लिए संरचना का विस्तार कर सकते हैं और पॉइंटर को void* के रूप में बदल सकते हैं और उस जंक को snprintf() या डेटा स्वरूपित करने के लिए पास कर सकते हैं।

कभी-कभी मैं एक मैक्रो का भी उपयोग करूंगा जो तालिका बनाने में मदद करता है (संभावित रूप से परिवर्तनीय घोषित करता है)। लेकिन ईमानदार होने के लिए, मुझे लगता है कि वास्तव में यह समझने के लिए और अधिक जटिल बनाता है (विशेष रूप से परियोजना में शामिल होने वाले किसी नए व्यक्ति के लिए - उनके पास अक्सर एक छोटा "डब्ल्यूटीएफ?" पल होता है) और चीजों को वास्तव में सरल नहीं करता है।

6

मेरे पास वास्तव में कुछ कोड है जो आप चाहते हैं जो कर सकते हैं। यह वैरिएबल नाम को स्ट्रिंग करने के लिए प्रीप्रोसेसर का उपयोग करता है ताकि आप इसे प्रिंट कर सकें। यह परिवर्तनीय नाम और मान (प्रकार के आधार पर) और उस चर के लिए स्मृति लेआउट दोनों को डंप करता है।निम्नलिखित कार्यक्रम से पता चलता है कि यह कैसे किया है:

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

static void dumpMem (unsigned char *p, unsigned int s) { 
    int i; 
    unsigned char c[0x10]; 
    printf (">>  "); 
    for (i = 0; i < 0x10; i++) printf (" +%x",i); 
    printf (" +"); 
    for (i = 0; i < 0x10; i++) printf ("%x",i); 
    printf ("\n"); 
    for (i = 0; i < ((s + 15) & 0xfff0); i++) { 
     if ((i % 0x10) == 0) { 
      if (i != 0) printf (" %*.*s\n", 0x10, 0x10, c); 
      printf (">> %04x ",i); 
     } 
     if (i < s) { 
      printf (" %02x", p[i]); 
      c[i & 0xf] = ((p[i] < 0x20) || (p[i] > 0x7e)) ? '.' : p[i]; 
     } else { 
      printf (" "); 
      c[i & 0xf] = ' '; 
     } 
    } 
    printf (" %*.*s\n", 0x10, 0x10, c); 
} 
#define DUMPINT(x) do{printf("%s: %d\n",#x,x);dumpMem((char*)(&x),sizeof(int));}while(0) 
#define DUMPSTR(x) do{printf("%s: %s\n",#x,x);dumpMem(x,strlen(x));}while(0) 
#define DUMPMEM(x,s) do{printf("%s:\n",#x);dumpMem((char*)(&x),s);}while(0) 

typedef struct { 
    char c; 
    int i; 
    char c2[6]; 
} tStruct; 

int main (void) { 
    int i = 42; 
    char *s = "Hello there, my name is Pax!"; 
    tStruct z; 
    z.c = 'a'; z.i = 42; strcpy (z.c2,"Hello"); 

    DUMPINT (i); 
    DUMPSTR (s); 
    DUMPMEM (z,sizeof(z)); 

    return 0; 
} 

यह आउटपुट:

i: 42 
>>  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +fabcdef 
>> 0000 2a 00 00 00          *... 
s: Hello there, my name is Pax! 
>>  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +fabcdef 
>> 0000 48 65 6c 6c 6f 20 74 68 65 72 65 2c 20 6d 79 20 Hello there, my 
>> 0010 6e 61 6d 65 20 69 73 20 50 61 78 21    name is Pax! 
z: 
>>  +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +a +b +c +d +e +fabcdef 
>> 0000 61 b6 16 61 2a 00 00 00 48 65 6c 6c 6f 00 0d 61 a..a*...Hello..a 

और, आप मैक्रो में do {...} while (0) के विवेक के बारे में सोच रहे हैं, कि में कहीं भी रखा जा करने के लिए सक्षम करने के लिए इस बारे में चिंता किए बिना कोड कि आपके पास इसके आस-पास पर्याप्त ब्रेसिज़ हैं या नहीं।

3

लोग अक्सर प्रोग्राम को आत्म-आत्मनिरीक्षण (या वर्तमान शब्दकोष में "प्रतिबिंबित" करना चाहते हैं)। लेकिन अधिकांश प्रोग्रामिंग भाषाएं प्रोग्राम (सभी नाम, फ़ंक्शन नाम, प्रकार, अभिव्यक्ति संरचनाएं इत्यादि) के सभी विवरणों पर प्रतिबिंबित करने के लिए छोटी (उदा। जावा) या कोई भी (सी) क्षमता प्रदान करती हैं।

सभी भाषाओं के लिए यह करने के लिए एक तरीका होता है: कदम बाहर भाषा, और एक उपकरण है कि भाषा से है कि जानकारी निकालने के लिए डिज़ाइन किया गया है का उपयोग करें। उपकरण की एक वर्ग जो इसे कर सकती है उसे प्रोग्राम ट्रांसफॉर्मेशन सिस्टम कहा जाता है।

इस अतः कैसे और प्रिंट मूल्यों एक कार्यक्रम परिवर्तन प्रणाली का उपयोग कर "चर नाम प्राप्त करने के लिए" की चर्चा के लिए जवाब देखें: Trace changes to variables automatically

0

इस प्रयास करें।

#define MACRO_VARIABLE_TO_STRING(Variable) ((void) Variable,#Variable) 

संहिता (शून्य) चर शून्य रूपांतरण जो कोई-op फिर वहाँ अल्पविराम ऑपरेटर और स्थूल stringify है है। तो शुद्ध परिणाम कॉन्सलर है जिसमें कंपाइलर चेक के साथ वैरिएबल नाम है वैरिएबल वास्तव में मौजूद है।

अब आपके पास अपने चर का नाम है और आप इसके मूल्य को मुद्रित करने के लिए printf() का उपयोग कर सकते हैं।

3

छोटा रास्ता:

#define GET_VARIABLE_NAME(Variable) (#Variable) 

परीक्षण:

#include <string> 
class MyClass {}; 


int main(int argc, char* argv[]) { 
    int foo = 0; 

    std::string var_name1 = GET_VARIABLE_NAME(foo); 
    char* var_name2 = GET_VARIABLE_NAME(foo); 
    char* var_name3 = GET_VARIABLE_NAME(MyClass); 


    return 0; 
}