2016-07-08 9 views
5

बदलता है मैं %d का उपयोग कर नाव प्रिंट करने की कोशिश (मुझे पता है कि यह नहीं किया जाना चाहिए। लेकिन हर बार फिर से चलाने के निष्पादन यह एक अलग मूल्य बाहर देता है)
मेरा प्रश्न है: मुद्रित मूल्य हर बार क्यों बदलता है? मेरे सिस्टम: Ubuntu 14.04 (64 बिट) संकलक: 4.8.4 यहाँ कोड है:सी चल बिन्दु% d मूल्य हर बार निष्पादित

#include<stdio.h> 

int main(){ 
    float b = 12.3456; 

    printf("%d\n",b); 

} 

नमूना उत्पादन:

[email protected]:~/C-fi$ ./test 
-1629995944 
[email protected]:~/C-fi$ ./test 
1147348376 
[email protected]:~/C-fi$ ./test 
-1746005432 
[email protected]:~/C-fi$ ./test 
510102216 
[email protected]:~/C-fi$ 
+8

* अपरिभाषित व्यवहार का एक अद्भुत उदाहरण * - आपको और जानने की क्या आवश्यकता है? – tofro

+0

मैं जानना चाहता हूं कि ऐसा क्यों हुआ? – 4bh1

+0

क्योंकि यह अपरिभाषित है? – tofro

उत्तर

7

शायद फ़्लोटिंग-बिंदु मान एफपीयू रजिस्टर के माध्यम से पारित कर दिया है, लेकिन printf() कहीं और से पूर्णांक पढ़ने की कोशिश करता है, जहां यह पूर्णांक (ढेर या अन्य रजिस्टर) देखने की अपेक्षा करता है। और उस जगह की सामग्री निर्दिष्ट नहीं है। कड़ाई से कह रहा है (जैसा कि @ डीबश ने उल्लेख किया है) आपका कोड अपरिभाषित व्यवहार का कारण बनता है।

+0

यह किसी भी एबीआई के अनुरूप नहीं होगा मुझे पता है, लेकिन कुछ एबीआई फ़्लोटिंग-पॉइंट मानों को '% f' के साथ मुद्रित करने के लिए पास करते हैं और रजिस्टरों में '% d' के साथ पूर्णांक मान मुद्रित किए जाते हैं, जो संभावित कोड (और एएसएलआर) के आधार पर हम जो देखते हैं उसे समझा सकते हैं। –

+1

उदा। x64 के लिए, https://msdn.microsoft.com/en-us/library/ms235286.aspx कहता है "तर्क आरसीएक्स, आरडीएक्स, आर 8, और आर 9 में पास किए जाते हैं। अगर तर्क फ़्लोट/डबल होते हैं, तो वे पास हो जाते हैं एक्सएमएम0 एल, एक्सएमएम 1 एल, एक्सएमएम 2 एल, और एक्सएमएम 3 एल में। " तो printf XMM0L में एक फ्लोट की उम्मीद कर रहा है लेकिन वह रजिस्टर आपके कोड द्वारा कभी भी सेट नहीं हुआ है। – moonshadow

+1

@PascalCuoq amd64 के लिए SysV ABI इस तरह है। – fuz

8

printf के लिए गलत प्रारूप विनिर्देश का उपयोग undefined behavior का एक उत्कृष्ट उदाहरण है। इसका मतलब है कि व्यवहार अप्रत्याशित है और इसे एक रन से अगले तक संगत होने पर निर्भर नहीं किया जा सकता है। यह क्रैश हो सकता है, यह यादृच्छिक मूल्य मुद्रित कर सकता है, या यह काम पर दिखाई दे सकता है।

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

यदि आप असेंबलर से परिचित हैं, तो आप संकलित कोड को देख सकते हैं कि यह कौन सा निर्देश उत्पन्न हुआ है। ध्यान रखें कि अलग-अलग कंपाइलर्स (यहां तक ​​कि विभिन्न अनुकूलन सेटिंग्स के साथ एक ही कंपाइलर) अधिकतर असेंबली उत्पन्न करेगा।

1

टिप्पणियों में संकेत के अनुसार, यह अपरिभाषित व्यवहार जैसा लगता है, जो बता रहा है (ठीक है, क्रमबद्ध) क्या हो रहा है।

मामले में आप एक नाव के आंतरिक प्रतिनिधित्व पढ़ना चाहते हैं, या आप नंबर पर कुछ निम्न स्तर हैक्स क्या करना चाहते हैं, वहाँ सरल तरीके है उदाहरण के लिए, ऐसा करने के लिए:

union { 
    float f; 
    int i; 
} n; 

n.f = 12.3456; 
printf("%d\n", n.i); // should be the same number each time 

ध्यान दें कि यह केवल तभी काम करता है जब float और int आपके सिस्टम पर एक ही आकार है, लेकिन अधिकतर लोगों के लिए मामला होना चाहिए। यदि आप सुनिश्चित करना चाहते हैं तो आप assert(sizeof(float) == sizeof(int)) जोड़ सकते हैं।

+0

कड़ाई से यह कहते हुए कि 'यूनियन' हैक कम से कम पोर्टेबल है क्योंकि फ़ील्ड अलग-अलग संरेखण नियमों के कारण ओवरलैप नहीं हो सकता है। यह 'memcpy() 'के साथ करना बेहतर होगा। – Sergio

+1

@ सेरियोओ 'यूनियन' की शुरुआत में कभी भी कोई पैडिंग नहीं है, तो सदस्यों को ओवरलैप क्यों नहीं किया जाएगा? आईएसओ/आईईसी 98 99: 2011 § 6.7.2.1 (15) '... एक संरचना ऑब्जेक्ट के भीतर अज्ञात पैडिंग हो सकता है, लेकिन इसकी शुरुआत में नहीं। 'माना जाता है कि यह संघीय वस्तुओं का उल्लेख करने के लिए उपेक्षा करता है। –

+0

मेरी पिछली टिप्पणी के आगे, §6.5.3.4 (4) 'sizeof' के बारे में:' ... संरचना या यूनियन प्रकार वाले ऑपरेंड पर लागू होता है, परिणाम इस तरह के किसी ऑब्जेक्ट में बाइट्स की कुल संख्या है, जिसमें आंतरिक और पीछे की पैडिंग। 'इसमें अग्रणी पैडिंग का उल्लेख नहीं है, जो बताता है कि यह अस्तित्व में नहीं है। –

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