क्यों प्रिंटफ ("% f", 0); अपरिभाषित व्यवहार दें?


87

बयान

printf("%f\n",0.0f);

प्रिंट ०।

हालांकि, बयान

printf("%f\n",0);

यादृच्छिक मूल्यों को प्रिंट करता है।

मुझे लगता है कि मैं किसी तरह के अपरिभाषित व्यवहार का प्रदर्शन कर रहा हूं, लेकिन मैं यह पता नहीं लगा सकता कि विशेष रूप से क्यों।

एक फ्लोटिंग पॉइंट वैल्यू जिसमें सभी बिट्स 0 हैं, अभी भी float0. के वैल्यू के साथ वैलिड है
floatऔर intमेरी मशीन पर एक ही साइज की है (यदि वह प्रासंगिक भी है)।

printfइस व्यवहार के कारण फ्लोटिंग पॉइंट शाब्दिक के बजाय पूर्णांक शाब्दिक का उपयोग क्यों किया जाता है ?

PS एक ही व्यवहार देखा जा सकता है अगर मैं उपयोग करता हूं

int i = 0;
printf("%f\n", i);

37
printfउम्मीद कर रहा है doubleऔर आप इसे दे रहे हैं a intfloatऔर intआपकी मशीन पर समान आकार हो सकता है, लेकिन 0.0fवास्तव में doubleजब इसे एक वैरिएड तर्क सूची में धकेल दिया जाता है (और printfउम्मीद करता है)। संक्षेप में, आप printfअपने उपयोग और आपके द्वारा प्रदान किए गए तर्कों के आधार पर सौदेबाजी के अपने अंत को पूरा नहीं कर रहे हैं।
WhozCraig

22
Varargs- फ़ंक्शन स्वचालित रूप से फ़ंक्शन तर्कों को संबंधित पैरामीटर के प्रकार में परिवर्तित नहीं करते हैं, क्योंकि वे नहीं कर सकते हैं। प्रोटोटाइप के साथ गैर-वैरग कार्यों के विपरीत, आवश्यक जानकारी संकलक के लिए उपलब्ध नहीं है।
EOF

3
ऊह ... "चर।" मैंने अभी एक नया शब्द सीखा है ...
माइक रॉबिन्सन


3
कोशिश करने के लिए अगले बात एक पारित करने के लिए है (uint64_t)0के बजाय 0और देखें कि क्या आप अभी भी यादृच्छिक व्यवहार मिलता है (यह मानते हुए doubleऔर uint64_tएक ही आकार और संरेखण है)। संभावना है कि विभिन्न रजिस्टरों में पारित होने के कारण कुछ प्लेटफार्मों (जैसे x86_64) पर आउटपुट अभी भी यादृच्छिक होगा।
इयान एबॉट

जवाबों:


121

"%f"प्रारूप प्रकार की एक बहस की आवश्यकता है double। आप इसे प्रकार का तर्क दे रहे हैं int। इसीलिए व्यवहार अपरिभाषित है।

मानक की गारंटी नहीं है कि सभी बिट शून्य का एक मान्य प्रतिनिधित्व है 0.0(हालांकि यह अक्सर होता है), या किसी के doubleमूल्य, या कि intऔर doubleएक ही आकार के होते हैं (याद यह है double, नहींfloat ), या, भले ही वे एक ही हैं आकार, कि वे उसी तरह एक चर समारोह के लिए तर्क के रूप में पारित कर रहे हैं।

यह आपके सिस्टम पर "काम" करने के लिए हो सकता है। यह अपरिभाषित व्यवहार का सबसे खराब संभव लक्षण है, क्योंकि यह त्रुटि का निदान करना मुश्किल बनाता है।

N1570 7.21.6.1 पैरा 9:

... यदि कोई तर्क संगत रूपांतरण विनिर्देश के लिए सही प्रकार नहीं है, तो व्यवहार अपरिभाषित है।

प्रकार के तर्क floatको बढ़ावा दिया जाता है double, यही वजह है कि printf("%f\n",0.0f)काम करता है। पूर्णांक प्रकार के संकरेपन की तुलना में intइसे बढ़ावा दिया जाता intहै unsigned int। ये पदोन्नति नियम (N1570 6.5.2.2 पैराग्राफ 6 द्वारा निर्दिष्ट) के मामले में मदद नहीं करते हैं printf("%f\n", 0)

ध्यान दें कि यदि आप 0एक गैर-वैरिएड फ़ंक्शन के लिए एक निरंतर पास करते हैं जो एक doubleतर्क की अपेक्षा करता है, तो व्यवहार को अच्छी तरह से परिभाषित किया जाता है, यह मानते हुए कि फ़ंक्शन का प्रोटोटाइप दिखाई देता है। उदाहरण के लिए, sqrt(0)(बाद में #include <math.h>) तर्क को तर्क 0से रूपांतरित करता intहै double- क्योंकि संकलक इस घोषणा से देख सकता है sqrtकि यह doubleतर्क की अपेक्षा करता है। इसके लिए ऐसी कोई जानकारी नहीं है printf। वैरिएडिक फ़ंक्शन जैसे printfविशेष हैं, और उन्हें कॉल लिखने में अधिक देखभाल की आवश्यकता होती है।


13
उत्कृष्ट कोर बिंदुओं की एक जोड़ी यहाँ। सबसे पहले, यह ऐसा doubleनहीं floatहै कि ओपी की चौड़ाई की धारणा (शायद नहीं) पकड़ नहीं सकती है। दूसरा, यह धारणा कि पूर्णांक शून्य और फ्लोटिंग-पॉइंट शून्य में एक ही बिट पैटर्न है, जो धारण नहीं करता है। अच्छा काम
लाइटवेट रेस इन ऑर्बिट

2
@LucasTrzesniewski: ठीक है, लेकिन मैं यह नहीं देखता कि मेरा जवाब किस तरह से सवाल का जवाब देता है। मैं राज्य ने ऐसा ही किया floatकरने के लिए प्रोत्साहित किया जाता है doubleइसकी वजह समझाने के बिना, लेकिन यह मुख्य बिंदु नहीं था।
कीथ थॉम्पसन

2
@ robertbristow-johnson: संकलक के लिए विशेष हुक की आवश्यकता नहीं है printf, हालांकि gcc, उदाहरण के लिए, इसमें कुछ त्रुटियां हैं ( यदि प्रारूप स्ट्रिंग शाब्दिक है) तो इसका निदान कर सकते हैं । संकलक की घोषणा देख सकते हैं printfसे <stdio.h>है, जो यह बताता है कि पहले पैरामीटर एक है const char*और बाकी से दर्शाया जाता है , ...। नहीं, %fके लिए double(और floatपदोन्नत किया गया है double), और %lfके लिए है long double। सी मानक एक स्टैक के बारे में कुछ नहीं कहता है। यह printfकेवल तभी व्यवहार को निर्दिष्ट करता है जब इसे सही ढंग से कहा जाता है।
कीथ थॉम्पसन

2
@ robertbristow-johnson: पुराने समय में, "लिंट" ने अक्सर कुछ अतिरिक्त जाँच की जो अब gcc करती है। एक को floatपारित करने के printfलिए पदोन्नत किया गया है double; इसके बारे में कुछ भी जादुई नहीं है, यह केवल वैरेडिक फ़ंक्शन को कॉल करने के लिए एक भाषा नियम है। printfखुद को प्रारूप स्ट्रिंग के माध्यम से जानता है कि कॉलर ने इसे पारित करने का क्या दावा किया था; यदि यह दावा गलत है, तो व्यवहार अपरिभाषित है।
कीथ थॉम्पसन

2
छोटे सुधार: lलंबाई आपरिवर्तक "एक के बाद पर कोई प्रभाव नहीं a, A, e, E, f, F, g, या Gरूपांतरण विनिर्देशक", एक के लिए लंबाई संशोधक long doubleरूपांतरण है L। (@ robertbristow-johnson भी दिलचस्पी ले सकता है)
डेनियल फिशर

58

सबसे पहले, जैसा कि कई अन्य उत्तरों में स्पर्श किया गया है, लेकिन मेरे दिमाग में नहीं, स्पष्ट रूप से पर्याप्त रूप से लिखा गया है: यह अधिकांश संदर्भों में एक पूर्णांक प्रदान करने के लिए काम करता है जहां एक लाइब्रेरी फ़ंक्शन या तर्क लेता है । संकलक स्वचालित रूप से एक रूपांतरण सम्मिलित करेगा। उदाहरण के लिए, अच्छी तरह से परिभाषित है और बिल्कुल वैसा ही व्यवहार करेगा , और वहां उपयोग किए गए किसी भी अन्य पूर्णांक-प्रकार की अभिव्यक्ति के लिए भी यही सच है।doublefloatsqrt(0)sqrt((double)0)

printfफरक है। यह भिन्न है क्योंकि यह तर्कों की एक चर संख्या लेता है। इसका फंक्शन प्रोटोटाइप है

extern int printf(const char *fmt, ...);

इसलिए, जब आप लिखते हैं

printf(message, 0);

कंपाइलर को इस बारे में कोई जानकारी नहीं है कि किस प्रकार के दूसरे तर्क की printf अपेक्षा है। इसमें केवल तर्क अभिव्यक्ति का प्रकार है, जो हैint द्वारा जाना है। इसलिए, अधिकांश पुस्तकालय कार्यों के विपरीत, यह आप पर है, प्रोग्रामर, यह सुनिश्चित करने के लिए कि तर्क सूची प्रारूप स्ट्रिंग की अपेक्षाओं से मेल खाती है।

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

अब, सवाल का दूसरा आधा हिस्सा था: यह देखते हुए कि (int) 0 और (फ्लोट) 0.0 सबसे आधुनिक प्रणालियों पर हैं, दोनों को 32 बिट्स के रूप में दर्शाया गया है, जो सभी शून्य हैं, वैसे भी यह दुर्घटना से काम क्यों नहीं करता है? सी मानक केवल यह कहता है "यह काम करने के लिए आवश्यक नहीं है, आप अपने दम पर हैं", लेकिन मुझे दो सबसे सामान्य कारणों के बारे में बताएं कि यह काम क्यों नहीं करेगा; यह शायद आपको यह समझने में मदद करेगा कि क्यों यह आवश्यकता नहीं है।

सबसे पहले, ऐतिहासिक कारणों से, जब आप floatएक चर तर्क सूची से गुजरते हैं, तो इसका प्रचार हो जाता है double, जो कि अधिकांश आधुनिक प्रणालियों पर, 64 बिट्स चौड़ा होता है। तो printf("%f", 0)उनमें से 64 को उम्मीद है कि केवल 32 शून्य बिट्स एक कैली को पास करता है।

दूसरा, समान रूप से महत्वपूर्ण कारण यह है कि फ्लोटिंग-पॉइंट फ़ंक्शन तर्क पूर्णांक तर्कों की तुलना में एक अलग स्थान पर पारित किए जा सकते हैं । उदाहरण के लिए, अधिकांश सीपीयू में पूर्णांक और फ्लोटिंग-पॉइंट मानों के लिए अलग-अलग रजिस्टर फाइलें होती हैं, इसलिए यह एक नियम हो सकता है कि तर्क 4 में से 4 r4 के माध्यम से रजिस्टरों r0 में जाते हैं यदि वे पूर्णांक हैं, लेकिन f0 के माध्यम से f0 अगर वे फ्लोटिंग-पॉइंट हैं। तो printf("%f", 0)उस शून्य के लिए रजिस्टर एफ 1 में दिखता है, लेकिन यह बिल्कुल भी नहीं है।


1
क्या कोई भी आर्किटेक्चर है जो वैरिएड कार्यों के लिए रजिस्टरों का उपयोग करता है, यहां तक ​​कि उन लोगों के बीच भी जो सामान्य कार्यों के लिए उपयोग करते हैं? मैंने सोचा था कि यही कारण है कि वैरिएड फ़ंक्शंस को ठीक से घोषित किए जाने की आवश्यकता होती है, जबकि अन्य फ़ंक्शंस [फ्लोट / शॉर्ट / चार तर्क वाले लोगों को छोड़कर] के साथ घोषित किए जा सकते हैं ()
रैंडम 832

3
@ Random832 आजकल, एक वैरेडिक और एक सामान्य फ़ंक्शन के कॉलिंग कन्वेंशन के बीच एकमात्र अंतर यह है कि वेरिएडिक को आपूर्ति किए गए कुछ अतिरिक्त डेटा हो सकते हैं, जैसे कि आपूर्ति किए गए तर्कों की सही संख्या की गिनती। अन्यथा सब कुछ ठीक उसी जगह पर होता है जहां यह एक सामान्य कार्य के लिए होता है। उदाहरण के लिए देखें x86-64.org/documentation/abi.pdf का खंड 3.2 , जहां वैरेडिक्स के लिए एकमात्र विशेष उपचार एक संकेत है जिसमें पारित किया गया है AL। (हां, इसका मतलब यह है कि लागू होने va_argकी तुलना में यह बहुत अधिक जटिल है।)
zwol

@ Random832: मैंने हमेशा सोचा था कि कारण यह था कि कुछ आर्किटेक्चर कार्यों पर एक ज्ञात संख्या और प्रकार के तर्कों को विशेष निर्देशों का उपयोग करके अधिक कुशलता से लागू किया जा सकता था।
celtschk

@celtschk आप SPARC और IA64 पर "रजिस्टर विंडो" के बारे में सोच रहे होंगे, जो कि छोटी संख्या में तर्कों के साथ फ़ंक्शन कॉल के सामान्य मामले में तेजी लाने वाले थे (अफसोस, व्यवहार में, वे इसके ठीक विपरीत करते हैं)। उन्हें वैरिएड फंक्शन कॉल्स का विशेष रूप से इलाज करने के लिए कंपाइलर की आवश्यकता नहीं होती है, क्योंकि किसी एक कॉल साइट पर तर्कों की संख्या हमेशा संकलन-समय स्थिर होती है, भले ही कैली वैडिक हो।
१२:२० पर जूल २ z

@zwol: नहीं, मैं सोच रहा था ret n 8086 निर्देश के , जहां nएक हार्ड-कोडेड पूर्णांक था, जो इसलिए वैरेडिक कार्यों के लिए लागू नहीं था। हालाँकि मुझे नहीं पता कि कोई सी संकलक वास्तव में इसका लाभ उठाता है (गैर-सी संकलक ने निश्चित रूप से किया है)।
celtschk

13

आमतौर पर जब आप एक फ़ंक्शन को कॉल करते हैं जो एक की अपेक्षा करता है double, लेकिन आप एक प्रदान करते हैं int, तो कंपाइलर स्वचालित रूप से doubleआपके लिए परिवर्तित हो जाएगा। ऐसा नहीं होता है printf, क्योंकि फ़ंक्शन प्रोटोटाइप में तर्कों के प्रकार निर्दिष्ट नहीं किए जाते हैं - कंपाइलर को पता नहीं है कि रूपांतरण लागू किया जाना चाहिए।


4
इसके अलावा, printf() विशेष रूप से डिजाइन किया गया है ताकि इसके तर्क किसी भी प्रकार के हो सकें। आपको पता होना चाहिए कि प्रारूप-स्ट्रिंग में प्रत्येक तत्व से किस प्रकार की उम्मीद है, और आपको इसे सही तरीके से प्रदान करना होगा।
माइक रॉबिन्सन

@ मायकेरोबिन्सन: खैर, कोई भी आदिम सी प्रकार। जो सभी संभावित प्रकारों का एक बहुत, बहुत छोटा उपसमूह है।
MSalters

13

फ्लोट शाब्दिक के बजाय पूर्णांक शाब्दिक का उपयोग करना इस व्यवहार का कारण क्यों बनता है?

क्योंकि 1 printf()के const char* formatstringरूप में इसके अलावा टाइप किए गए पैरामीटर नहीं हैं । यह ...बाक़ी सभी के लिए सी-स्टाइल इलिप्सिस ( ) का उपयोग करता है ।

यह सिर्फ यह तय करता है कि प्रारूप स्ट्रिंग में दिए गए स्वरूपण प्रकारों के अनुसार वहां दिए गए मूल्यों की व्याख्या कैसे करें।

जब आप कोशिश कर रहे हैं तो आपके पास अपरिभाषित व्यवहार होगा

 int i = 0;
 const double* pf = (const double*)(&i);
 printf("%f\n",*pf); // dereferencing the pointer is UB

3
कुछ विशेष कार्यान्वयन printfइस तरह से काम कर सकते हैं (सिवाय इसके कि आइटम पारित किए गए मान हैं, पते नहीं)। सी मानक यह निर्दिष्ट नहीं करता है कि कैसे printf और अन्य प्रकार्य कार्य काम करते हैं, यह सिर्फ उनके व्यवहार को निर्दिष्ट करता है। विशेष रूप से, स्टैक फ्रेम का कोई उल्लेख नहीं है।
कीथ थॉम्पसन

एक छोटा वक्रोक्ति: printfमें एक टाइप किया हुआ पैरामीटर होता है, प्रारूप स्ट्रिंग, जो टाइप का होता है const char*। BTW, प्रश्न C और C ++ दोनों को टैग किया गया है, और C वास्तव में अधिक प्रासंगिक है; मैं शायद reinterpret_castएक उदाहरण के रूप में इस्तेमाल नहीं किया होगा ।
कीथ थॉम्पसन

बस एक दिलचस्प अवलोकन: एक ही अपरिभाषित व्यवहार, और समान तंत्र के कारण सबसे अधिक संभावना है, लेकिन एक छोटे से अंतर के साथ विस्तार से: प्रश्न में एक इंट पास करना, यूबी प्रिंट के भीतर होता है जब इंट को डबल के रूप में व्याख्या करने की कोशिश की जाती है - आपके उदाहरण में , यह पहले से ही बाहर होता है जब dereferencing pf ...
Aconcagua

@Aconcagua स्पष्टीकरण जोड़ा गया।
atν 18α ῥεῖ

यह कोड नमूना सख्त एलियासिंग उल्लंघन के लिए यूबी है, जो सवाल पूछ रहा है उसके लिए एक पूरी तरह से अलग समस्या है। उदाहरण के लिए आप पूरी तरह से इस संभावना को नजरअंदाज कर देते हैं कि फ्लोटर्स विभिन्न रजिस्टरों में पूर्णांक में पारित हो जाते हैं।
MM

12

गलत मिलान वाले printf()विनिर्देशक "%f"और प्रकार का उपयोग (int) 0करने से अपरिभाषित व्यवहार होता है।

यदि कोई रूपांतरण विनिर्देश अमान्य है, तो व्यवहार अपरिभाषित है। C11dr 117.21.6.1 9

यूबी के उम्मीदवार कारण।

  1. यह प्रति युक्ति UB है और संकलन ऑनेरी है - 'nuf ने कहा।

  2. doubleऔर intविभिन्न आकारों के हैं।

  3. doubleऔर intअलग-अलग ढेर (सामान्य बनाम एफपीयू स्टैक) का उपयोग करके अपने मूल्यों को पारित कर सकते हैं ।

  4. एक double 0.0 हो सकता है एक सब शून्य बिट पैटर्न द्वारा परिभाषित नहीं किया जा। (दुर्लभ)


10

यह आपके संकलक की चेतावनियों से सीखने के उन बेहतरीन अवसरों में से एक है।

$ gcc -Wall -Wextra -pedantic fnord.c 
fnord.c: In function ‘main’:
fnord.c:8:2: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Wformat=]
  printf("%f\n",0);
  ^

या

$ clang -Weverything -pedantic fnord.c 
fnord.c:8:16: warning: format specifies type 'double' but the argument has type 'int' [-Wformat]
        printf("%f\n",0);
                ~~    ^
                %d
1 warning generated.

इसलिए, printfअपरिभाषित व्यवहार का उत्पादन कर रहा है क्योंकि आप इसे एक असंगत प्रकार का तर्क दे रहे हैं।


9

मुझे यकीन नहीं है कि क्या भ्रमित है।

आपका प्रारूप स्ट्रिंग की उम्मीद है double; आप इसके बजाय प्रदान करते हैंint

चाहे दो प्रकार की एक ही चौड़ाई हो पूरी तरह से अप्रासंगिक है, सिवाय इसके कि आपको इस तरह से टूटे हुए कोड से हार्ड मेमोरी उल्लंघन के अपवादों को प्राप्त करने से बचने में मदद मिल सकती है।


3
@Voo: उस प्रारूप स्ट्रिंग संशोधक का नाम दुर्भाग्य से रखा गया है, लेकिन मैं अभी भी यह नहीं देखता कि आप यह क्यों सोचेंगे कि intयहाँ स्वीकार्य होगा।
लाइटवेट रेस इन ऑर्बिट

1
@Voo: "(जो एक वैध फ्लोट पैटर्न के रूप में भी योग्य होगा)"int एक मान्य फ्लोट पैटर्न के रूप में योग्यता क्यों होगी ? दो के पूरक और विभिन्न फ्लोटिंग-पॉइंट एन्कोडिंग में लगभग कुछ भी सामान्य नहीं है।
लाइटवेट रेस इन ऑर्बिट

2
यह भ्रामक है, क्योंकि अधिकांश पुस्तकालय कार्यों के लिए, 0टाइप किए गए तर्क को पूर्णांक शाब्दिक प्रदान doubleकरना राइट थिंग करेगा। यह एक शुरुआत के लिए स्पष्ट नहीं है कि संकलक printfद्वारा संबोधित तर्क स्लॉट के लिए एक ही रूपांतरण नहीं करता है %[efg]
zwol

1
@Voo: अगर आप इस बात को लेकर बहुत गलत हैं कि यह कितना गलत हो सकता है, तो विचार करें कि x86-64 SysV ABI पर, फ्लोटिंग-पॉइंट तर्क अलग-अलग रजिस्टर-सेट में पूर्णांक तर्कों से पारित किए जाते हैं।
ईओएफ जूल

1
@LightnessRacesinOrbit मुझे लगता है कि यह चर्चा करना हमेशा उचित है कि कुछ यूबी क्यों है, जिसमें आमतौर पर इस बात की चर्चा होती है कि कार्यान्वयन अक्षांश की अनुमति क्या है और वास्तव में सामान्य मामलों में क्या होता है।
५० पर जूल

4

"%f\n"जब दूसरा printf()पैरामीटर का प्रकार होता है, तो केवल अनुमानित परिणाम की गारंटी देता है double। अगला, वैरिएड फ़ंक्शंस का एक अतिरिक्त तर्क डिफ़ॉल्ट तर्क पदोन्नति का विषय है। पूर्णांक तर्क पूर्णांक प्रचार के अंतर्गत आते हैं, जिसके परिणामस्वरूप कभी भी फ़्लोटिंग-पॉइंट टाइप किए गए मान नहीं होते हैं। और floatमापदंडों को बढ़ावा दिया जाता हैdouble

इसे बंद करने के लिए: मानक दूसरे तर्क को या floatया doubleकुछ और करने की अनुमति देता है।


4

क्यों औपचारिक रूप से यूबी अब कई उत्तरों में चर्चा की गई है।

कारण यह है कि आपको विशेष रूप से यह व्यवहार प्लेटफ़ॉर्म-निर्भर है, लेकिन संभवतः निम्नलिखित है:

  • printfमानक वार्ग प्रचार के अनुसार इसके तर्कों की अपेक्षा है। इसका मतलब है कि एक floatहोगा doubleऔर एक से छोटा कुछ भी एक intहोगा int
  • आप उस स्थान से गुजर रहे हैं intजहाँ फ़ंक्शन की उम्मीद है double। आपकी intशायद 32 बिट है, आपकी double64 बिट। इसका मतलब है कि चार स्टैक बाइट्स उस स्थान पर शुरू होती हैं जहां तर्क को बैठना चाहिए 0, लेकिन निम्नलिखित चार बाइट्स में मनमानी सामग्री होती है। इसका उपयोग मूल्य प्रदर्शित करने के लिए किया जाता है।

0

इस "अनिर्धारित मूल्य" समस्या का मुख्य कारण पॉइंटर के कास्ट में वैरिएबल पैरामीटर्स सेक्शन में intपास किए गए मान printfपर पॉइंटर के doubleप्रकार पर टिका होता है।va_arg है।

यह स्मृति क्षेत्र के लिए एक संदर्भ का कारण बनता है जो प्रिंट के पैरामीटर के रूप में पारित मूल्य के साथ पूरी तरह से आरंभिक नहीं था, क्योंकि doubleआकार मेमोरी बफर की तुलना में अधिक हैint आकार ।

इसलिए, जब यह पॉइंटर को डिफरेंस किया जाता है, तो इसे एक अनिर्धारित मूल्य लौटाया जाता है, या बेहतर "मान" होता है, जिसमें भाग के मान को पैरामीटर के रूप में पारित किया जाता है printf, और शेष भाग के लिए एक अन्य स्टैक बफर क्षेत्र या यहां तक ​​कि एक कोड क्षेत्र से आ सकता है ( एक मेमोरी फ़ॉल्ट अपवाद को बढ़ाते हुए), एक वास्तविक बफर अतिप्रवाह


यह "printf" और "va_arg" ... के प्रिंट कोड के इन विशिष्ट भागों पर विचार कर सकता है ...

printf

va_list arg;
....
case('%f')
      va_arg ( arg, double ); //va_arg is a macro, and so you can pass it the "type" that will be used for casting the int pointer argument of printf..
.... 


वास्तविक मूल्य वर्धमान में (gnu impl पर विचार करते हुए) दोहरे मान पैरामीटर कोड केस प्रबंधन है:

if (__ldbl_is_dbl)
{
   args_value[cnt].pa_double = va_arg (ap_save, double);
   ...
}



va_arg

char *p = (double *) &arg + sizeof arg;  //printf parameters area pointer

double i2 = *((double *)p); //casting to double because va_arg(arg, double)
   p += sizeof (double);



संदर्भ

  1. "प्रिंट" (vprintf) का कार्यान्वयन
  2. प्रिंटफ के सेम्पलिफ़िकेशन कोड का उदाहरण
  3. va_arg के संगोष्ठी कोड का उदाहरण
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.