2012-02-16 13 views
11

पर काम नहीं करता है मेरे पास एक ऐसा फ़ंक्शन है जो कंसोल पर लॉग ऑन करने और लॉग फ़ाइल में लॉग करने का प्रयास करता है, लेकिन यह काम नहीं करता है। परिवर्तनीय लंबाई तर्क का दूसरा उपयोग कंसोल को कचरा लिखा जाता है। कोई विचार?एक वैरिएडिक फ़ंक्शन तर्क का बार-बार उपयोग

void logPrintf(const char *fmt, ...) { 
     va_list ap; // log to logfile 
     va_start(ap, fmt); 
     logOpen; 
     vfprintf(flog, fmt, ap); 
     logClose; 
     va_end(ap); 
     va_list ap2; // log to console 
     va_start(ap2, fmt); 
     printf(fmt, ap2); 
     va_end(ap2); 
    } 
+1

आपको दूसरी बार vprintf का उपयोग करने की आवश्यकता है, printf नहीं। –

उत्तर

-2

मुझे लगता है कि इस तरह से अधिक समझ में आता है:

void logPrintf(const char *fmt, ...) { 
     va_list ap; // log to logfile 
     va_start(ap, fmt); 
     logOpen; 
     vfprintf(flog, fmt, ap); //logfile 
     printf(fmt, ap); //console 
     logClose; 
     va_end(ap); 
    } 
+0

धन्यवाद टोनी, लेकिन यह या तो काम नहीं करता है। ऐसा लगता है कि सूची के अंत में पॉइंटर छोड़ा जाता है, इसलिए दूसरा उपयोग कचरा हो जाता है। – Neddie

+0

हाँ, यह वही है जो हो रहा है। 'va_list's हमेशा पास-दर-संदर्भ होते हैं। –

+1

यह उदाहरण ('printf' के बजाय' vprintf' के साथ भी) मैन पेज के अनुसार गलत है: "अगर एपी को एक फ़ंक्शन में पास किया जाता है जो va_arg (ap, type) का उपयोग करता है तो एपी का मान वापस आने के बाद अपरिभाषित होता है वह समारोह। " लिनक्स x86-32 पर यह इरादे के रूप में काम करता है, लेकिन उदा। x86-64 पर। –

2

अपने संकलक अपग्रेड, कि और अधिक सी की तरह है ++:

template <typename... Args> 
void logPrintf(const char *fmt, Args&&... args) { 
    logOpen; 
    fprintf(flog, fmt, args...); 
    logClose; 

    printf(fmt, args...); 
} 

हालांकि निश्चित रूप से यह तो प्रदान करने के लिए अच्छा स्वाद होगा printf और fprintf के टाइपएफ़ संस्करण।

+0

उदाहरण के लिए सी ++ 11 की आवश्यकता है। –

+1

@ डेविडगिवेन: हाँ (इस प्रकार * आपके कंपाइलर को अपग्रेड करें *)। –

+0

मुझे लगता है कि vfprintf को इसके बजाय fprintf होना चाहिए - आप va_list के बजाय वास्तविक तर्क पारित कर रहे हैं। –

8

मूल कोड विफल रहता है क्योंकि यह printf() का उपयोग करने का प्रयास करता है जहां इसे vprintf() का उपयोग करने की आवश्यकता होती है। अंकित मूल्य पर logOpen और logClose बयान की तरह संदिग्ध अंक ले रहा है (संकेतन दिया, शायद वे मैक्रो जो खुले हैं और flog फ़ाइल धारा को बंद), कोड होना चाहिए:

void logPrintf(const char *fmt, ...) { 
    va_list ap; 
    va_start(ap, fmt); 
    logOpen; 
    vfprintf(flog, fmt, ap); 
    logClose; 
    va_end(ap); 
    va_list ap2; 
    va_start(ap2, fmt); 
    vprintf(fmt, ap2); 
    va_end(ap2); 
} 

उपयोग करने के लिए कोई विशेष जरूरत नहीं है दो अलग va_list चर; va_start() का उपयोग करने से पहले आप va_end() का उपयोग करते समय एक ही बार का उपयोग करने के लिए बिल्कुल ठीक है।

void logPrintf(const char *fmt, ...) { 
    va_list ap; 
    va_start(ap, fmt); 
    logOpen; 
    vfprintf(flog, fmt, ap); 
    logClose; 
    va_end(ap); 
    va_start(ap, fmt); 
    vprintf(fmt, ap); 
    va_end(ap); 
} 

एक va_list मूल्य एक अन्य समारोह (vfprintf() और vprintf() इस कोड में) करने के लिए पारित हो जाता है, तो आप मान लेना चाहिए कि यह वर्तमान समारोह में उपयोग नहीं किया जा रहा है। va_end() पर कॉल करना केवल सुरक्षित है।

इस कोड में va_copy() की कोई आवश्यकता नहीं है। यह काम करता है, लेकिन इसकी आवश्यकता नहीं है। आप इस तरह के अपने कार्य एक va_list पारित हो जाता है जब के रूप में अन्य परिस्थितियों में va_copy() की जरूरत है और आप दो बार सूची संसाधित करने की जरूरत:

void logVprintf(const char *fmt, va_list args1) 
{ 
    va_list args2; 
    va_copy(args2, args1); 
    logOpen; 
    vfprintf(flog, fmt, args1); 
    logClose; 
    vprintf(fmt, args2); 
    va_end(args2); 
} 

ध्यान दें कि इस कोड में, यह args1 पर va_end() कॉल करने के लिए बुला कोड की जिम्मेदारी है। दरअसल, मानक का कहना है:

va_start और va_copy मैक्रो से प्रत्येक मंगलाचरण एक ही समारोह में va_end मैक्रो के एक इसी मंगलाचरण से मिलान किया जाएगा।

के बाद से logVprintf() समारोह args1 प्रारंभ करने में या तो va_start या va_copy फोन नहीं है, यह वैध तरीके से va_endargs1 पर कॉल नहीं कर सकते। दूसरी तरफ, मानक को args2 के लिए va_end पर कॉल करने की आवश्यकता है।

logPrintf() समारोह अब logVprintf() के मामले में लागू किया जा सकता:

void logPrintf(const char *fmt, ...) 
{ 
    va_list args; 
    va_start(args, fmt); 
    logVprintf(fmt, args); 
    va_end(args); 
} 

यह संरचना - एक संचालन समारोह है कि एक va_list और एक कवर समारोह है कि दीर्घवृत्त (चर तर्क) लेता है और उन्हें परिचालन के पास ले जाता है va_list में रूपांतरण के बाद फ़ंक्शन - अक्सर काम करने का एक अच्छा तरीका है। जल्दी या बाद में, आपको आमतौर पर va_list तर्क के साथ संस्करण की आवश्यकता मिलती है।

+2

यह सही उत्तर है जो सीधे अपने वास्तुकला को बदलने की सिफारिश किए बिना ओपी के प्रश्न को हल करता है। – Vortico

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