2013-04-15 10 views
5

वैरैडिक टेम्पलेट्स printf फ़ंक्शन के कई कार्यान्वयन हैं।वैराडिक टेम्पलेट्स और टाइपफैटी

void printf(const char* s) { 
    while (*s) { 
    if (*s == '%' && *++s != '%') 
     throw std::runtime_error("invalid format string: missing arguments"); 
    std::cout << *s++; 
    } 
} 

template<typename T, typename... Args> 
void printf(const char* s, const T& value, const Args&... args) { 
    while (*s) { 
    if (*s == '%' && *++s != '%') { 
     std::cout << value; 
     return printf(++s, args...); 
    } 
    std::cout << *s++; 
    } 
    throw std::runtime_error("extra arguments provided to printf"); 
} 

और हर जगह कहा जाता है कि इस कार्यान्वयन टाइप-सुरक्षित जबकि सामान्य सी (variadic तर्क va_arg के साथ) नहीं है कि: एक यह है।

वह क्यों है? टाइप-सुरक्षित होने का क्या अर्थ है और सी printf va_arg पर इस कार्यान्वयन के क्या फायदे हैं?

+3

यह संस्करण प्रारूप झंडे के बारे में बिल्कुल परवाह नहीं करता है, यह सिर्फ स्ट्रीम ऑपरेटरों के माध्यम से सामान प्रिंट करता है। – Xeo

+1

यह सुरक्षित है कि 'टी' हमेशा पारित पैरामीटर का प्रकार होगा। मानक printf नहीं जानता है। –

+1

एक तरफ के रूप में, यह एक भयानक टाइपएफ़ 'printf' कार्यान्वयन है।यह प्रारूप विनिर्देशकों को अनदेखा करता है और गलत व्याख्या करता है, और अस्थायी मूल्यों को आगे बढ़ाने का भी समर्थन नहीं करता है! संक्षेप में, यह एक टाइपएफ़ फ़ंक्शन है, लेकिन यह इसके नाम के बावजूद 'printf' का वैध कार्यान्वयन नहीं है। एक अच्छा टाइपएफ़ 'printf' सुरक्षित होने पर 'printf' के समान व्यवहार करेगा, और असुरक्षित मामलों में अपरिभाषित करने में विफल रहेगा। – Yakk

उत्तर

4

होने के नाते सुरक्षित, या प्रकार सुरक्षित, इसका मतलब है कि आप स्रोत कोड को देख से बता सकते हैं अपने कार्यक्रम सही ढंग से कार्य करता है।

कथन std::cout << x हमेशा सही है, यह मानते हुए कि x में एक अच्छी तरह से परिभाषित मूल्य है (और कहता है, अनियंत्रित नहीं है); यह ऐसा कुछ है जिसे आप स्रोत कोड को देखने से गारंटी दे सकते हैं।

constrast करके, सी है नहीं सुरक्षित: उदाहरण के लिए, निम्न कोड या नहीं सही, क्रम इनपुट के आधार पर हो सकता है :

int main(int argc, char * argv[]) 
{ 
    if (argc == 3) 
     printf(argv[1], argv[2]); 
} 

यह सही है यदि और केवल यदि पहला तर्क एक मान्य प्रारूप स्ट्रिंग है जिसमें ठीक से एक "%s" होता है।

दूसरे शब्दों में, एक सही सी प्रोग्राम लिखना संभव है, लेकिन कोड का निरीक्षण करके शुद्धता के बारे में तर्क करना असंभव है। printf फ़ंक्शन एक ऐसा उदाहरण है। अधिक आम तौर पर, वेरिएबल तर्क स्वीकार करने वाला कोई भी फ़ंक्शन असुरक्षित रूप से असुरक्षित होता है, जैसा कि कोई भी फ़ंक्शन है जो रनटाइम मानों के आधार पर पॉइंटर्स को रोकता है।

+0

+1 एक बेहतर रनटाइम-इनपुट-निर्भर निष्पादन स्थिति के लिए उस नमूना को हरा करना मुश्किल है। और उसके ऊपर एक उत्कृष्ट जवाब। – WhozCraig

5

उन सभी तर्कों के लिए जो आप विविध टेम्पलेट संस्करण में जाते हैं, उनके प्रकार संकलन समय पर ज्ञात हैं। यह ज्ञान फ़ंक्शन के भीतर संरक्षित है। प्रत्येक ऑब्जेक्ट को cout पर भारी अधिभारित operator<< के साथ पास किया जाता है। पारित होने वाले प्रत्येक प्रकार के लिए, इस फ़ंक्शन का एक अलग अधिभार है। दूसरे शब्दों में, यदि आप int पास करते हैं, तो यह ostream::operator<<(int) पर कॉल कर रहा है, यदि आप डबल पास करते हैं, तो यह ostream::operator<<(double) पर कॉल कर रहा है। तो फिर, प्रकार संरक्षित है। और उनमें से प्रत्येक कार्य प्रत्येक प्रकार को उचित तरीके से संभालने के लिए विशिष्ट है। वह प्रकार की सुरक्षा है।

सी printf के साथ, कहानी अलग है। प्रकार फ़ंक्शन के अंदर संरक्षित नहीं है। इसे प्रारूप स्ट्रिंग की सामग्री के आधार पर इसे समझने की आवश्यकता है (जो रनटाइम मान हो सकता है)। फ़ंक्शन को केवल यह मानना ​​है कि तर्क प्रकारों से मेल खाने के लिए एक सही प्रारूप स्ट्रिंग पास की गई थी। संकलक इसे लागू नहीं करता है।

एक और प्रकार की सुरक्षा भी है, और यह तर्कों की संख्या में है। यदि आप सी printf फ़ंक्शन पर बहुत कम तर्क देते हैं, तो प्रारूप स्ट्रिंग से मेल खाने के लिए पर्याप्त नहीं है, तो आपके पास अपरिभाषित व्यवहार है। यदि आप वैरिएडिक टेम्पलेट के साथ एक ही काम करते हैं, तो आपको एक अपवाद मिलता है, जो वांछनीय नहीं है, निदान करने के लिए एक बहुत ही आसान समस्या है।

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