प्रिंटफ / स्प्रिंटफ के चर संख्याओं को कैसे पास किया जाए


83

मेरे पास एक वर्ग है जो एक "त्रुटि" फ़ंक्शन रखता है जो कुछ पाठ को प्रारूपित करेगा। मैं तर्कों की एक चर संख्या को स्वीकार करना चाहता हूं और फिर प्रिंटफ का उपयोग करके उन्हें प्रारूपित करता हूं।

उदाहरण:

class MyClass
{
public:
    void Error(const char* format, ...);
};

त्रुटि विधि को पैरामीटर में लिया जाना चाहिए, इसे प्रारूपित करने के लिए प्रिंटफ / स्प्रिंटफ को कॉल करें और फिर इसके साथ कुछ करें। मैं सभी फ़ॉर्मेटिंग को स्वयं लिखना नहीं चाहता हूँ, इसलिए यह समझने की कोशिश करता है कि मौजूदा फ़ॉर्मेटिंग का उपयोग कैसे किया जाए।

जवाबों:


152
void Error(const char* format, ...)
{
    va_list argptr;
    va_start(argptr, format);
    vfprintf(stderr, format, argptr);
    va_end(argptr);
}

यदि आप इसे प्रदर्शित करने से पहले स्ट्रिंग में हेरफेर करना चाहते हैं और वास्तव में इसे बफर में संग्रहीत करने की आवश्यकता है, तो vsnprintfइसके बजाय उपयोग करें vsprintfvsnprintfएक आकस्मिक बफर अतिप्रवाह त्रुटि को रोक देगा।


37

vsnprintf पर एक नज़र डालें क्योंकि इससे वही होगा जो आप चाहते हैं http://www.cplusplus.com/reference/clibrary/cstdio/vsprintf/

आपको पहले va_list arg array को init करना होगा, फिर उसे कॉल करना होगा।

उस लिंक से उदाहरण: / * vsprintf उदाहरण * /

#include <stdio.h>
#include <stdarg.h>

void Error (char * format, ...)
{
  char buffer[256];
  va_list args;
  va_start (args, format);
  vsnprintf (buffer, 255, format, args);


  //do something with the error

  va_end (args);
}

6
vsnprintf का दूसरा तर्क बफर लंबाई होना चाहिए, जिसमें समाप्ति बाइट ('0') भी शामिल है। तो आप 255 के बजाय फ़ंक्शन कॉल में 256 का उपयोग कर सकते हैं।
एविग्नेस्टो

और पासिंग मैजिक नंबर BAD है ... sizeof(buffer)256 के बजाय उपयोग करें।
अनाम '

4

मुझे स्टैक ओवरफ्लो में मौजूदा प्रश्नों पर अधिक पढ़ना चाहिए।

C ++ पासिंग वेरिएबल नंबर ऑफ़ आर्ग्यूमेंट्स एक समान प्रश्न है। माइक एफ की निम्नलिखित व्याख्या है:

जब तक आप शरारती और गैर-पोर्टेबल चाल में नहीं आना चाहते हैं, तब तक यह जानने के बिना कि आपको कितने तर्क दिए जा रहे हैं, यह जानने के बिना कॉल करने का कोई तरीका नहीं है।

आम तौर पर इस्तेमाल किया जाने वाला समाधान हमेशा वैरग फ़ंक्शन का एक वैकल्पिक रूप प्रदान करना है, इसलिए प्रिंटफ़ में vprintf है, जो va_list के स्थान पर ले जाता है .... वर्जन va_list संस्करणों के चारों ओर केवल आवरण होते हैं।

यही वह है जिसकी तलाश में मैं हूं। मैंने इस तरह एक परीक्षण कार्यान्वयन किया:

void Error(const char* format, ...)
{
    char dest[1024 * 16];
    va_list argptr;
    va_start(argptr, format);
    vsprintf(dest, format, argptr);
    va_end(argptr);
    printf(dest);
}

अंतिम 'प्रिंटफ (भाग्य);' दुर्भावनापूर्ण है - इसे कम से कम एक प्रारूप स्ट्रिंग की भी आवश्यकता है।
जोनाथन लेफ़लर

यह स्ट्रिंग नहीं है क्योंकि स्ट्रिंग प्रारूप स्ट्रिंग है यानी प्रिंटफ ("एक स्ट्रिंग"); ठीक है
Lodle

4
आप "% s" या "% d" समाहित होने तक प्रिंटफ (भाग्य) के साथ भाग सकते हैं, फिर BOOM । कृपया प्रिंटफ ("% s", डेस्ट) का उपयोग करें।
जॉन कुगेलमैन

बस यह बताना चाहते हैं कि कोर डंप सबसे अच्छा मामला है, सर्वर कोड और हैकर्स के पास नाश्ते के लिए आपका सीपीयू होगा।
20

"% .16383 s" का उपयोग करने का प्रयास करें और यह सरणी को ओवरफ्लो से बचाएगा। ('0' टर्मिनेटर के लिए अनुमति दें)
eddyq

3

आप परिवर्तनशील कार्यों की तलाश कर रहे हैं । प्रिंटफ () और स्प्रिंटफ () चर कार्य हैं - वे एक चर संख्या के तर्कों को स्वीकार कर सकते हैं।

यह मूल रूप से इन चरणों को पूरा करता है:

  1. पहले पैरामीटर को उन मापदंडों की संख्या के बारे में कुछ संकेत देना चाहिए जो पालन करते हैं। तो प्रिंटफ () में, "प्रारूप" पैरामीटर यह संकेत देता है - यदि आपके पास 5 प्रारूप निर्दिष्टकर्ता हैं, तो यह 5 और तर्क (कुल 6 तर्कों के लिए) की तलाश करेगा। पहला तर्क पूर्णांक हो सकता है (उदाहरण के लिए) (3, ए, बी, सी) "जहां" 3 "" 3 तर्कों को दर्शाता है)

  2. फिर va_start () आदि फ़ंक्शन का उपयोग करके, प्रत्येक क्रमिक तर्क के माध्यम से लूप और पुनर्प्राप्त करें।

ऐसा करने के लिए ट्यूटोरियल के बहुत सारे हैं - सौभाग्य!


3

दीर्घवृत्त के साथ कार्यों का उपयोग करना बहुत सुरक्षित नहीं है। यदि प्रदर्शन लॉग फ़ंक्शन के लिए महत्वपूर्ण नहीं है, तो ऑपरेटर को ओवरलोडिंग के रूप में उपयोग करने पर विचार करें :: प्रारूप। आप कुछ इस तरह लिख सकते हैं:

#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;

class formatted_log_t {
public:
    formatted_log_t(const char* msg ) : fmt(msg) {}
    ~formatted_log_t() { cout << fmt << endl; }

    template <typename T>
    formatted_log_t& operator %(T value) {
        fmt % value;
        return *this;
    }

protected:
    boost::format                fmt;
};

formatted_log_t log(const char* msg) { return formatted_log_t( msg ); }

// use
int main ()
{
    log("hello %s in %d-th time") % "world" % 10000000;
    return 0;
}

निम्नलिखित नमूना दीर्घवृत्त के साथ संभावित त्रुटियों को प्रदर्शित करता है:

int x = SOME_VALUE;
double y = SOME_MORE_VALUE;
printf( "some var = %f, other one %f", y, x ); // no errors at compile time, but error at runtime. compiler do not know types you wanted
log( "some var = %f, other one %f" ) % y % x; // no errors. %f only for compatibility. you could write %1% instead.

5
यह है कि किसी आसान चीज को कठिन कैसे बनाया जाए।
17

2
"दीर्घवृत्त के साथ कार्यों का उपयोग करना बहुत सुरक्षित नहीं है।" यदि आपके एकमात्र सुरक्षित विकल्प में c ++ और बूस्ट शामिल हैं, तो आपको यह समझाना चाहिए कि आपके द्वारा "बहुत सुरक्षित नहीं" से क्या मतलब है, और यह उल्लेख करें कि यदि आप सही प्रारूप विनिर्देशक का उपयोग करते हैं तो प्रिंटफ फ़ंक्शन पूरी तरह से सुरक्षित हैं।
ऑसविन जूल 27'17

2

नीचे सरल उदाहरण है। ध्यान दें कि आपको एक बड़े बफर में पास होना चाहिए, और यह देखने के लिए परीक्षण करें कि क्या बफर काफी बड़ा था या नहीं

void Log(LPCWSTR pFormat, ...) 
{
    va_list pArg;
    va_start(pArg, pFormat);
    char buf[1000];
    int len = _vsntprintf(buf, 1000, pFormat, pArg);
    va_end(pArg);
    //do something with buf
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.