यह कार्यक्रम कैसे काम करता है?


88
#include <stdio.h>

int main() {
    float a = 1234.5f;
    printf("%d\n", a);
    return 0;
}

यह एक प्रदर्शित करता है 0!! वो कैसे संभव है? तर्क क्या है?


मैं जानबूझ कर एक डाल दिया है %dमें printfके व्यवहार का अध्ययन करने के लिए बयान printf

जवाबों:


239

ऐसा इसलिए %dहै क्योंकि आपको उम्मीद है कि intआपने एक फ्लोट प्रदान किया है।

फ्लोट प्रिंट करने के लिए %e/ %f/ %gका उपयोग करें ।


0 क्यों मुद्रित किया जाता है: फ़्लोटिंग पॉइंट नंबर को doubleभेजने से पहले कनवर्ट किया जाता है printf। छोटे एंडियन में दोहरे प्रतिनिधित्व में संख्या 1234.5 है

00 00 00 00  00 4A 93 40

एक %d32-बिट पूर्णांक का उपभोग करता है, इसलिए एक शून्य मुद्रित होता है। (परीक्षण के रूप में, आप printf("%d, %d\n", 1234.5f);आउटपुट पर प्राप्त कर सकते हैं 0, 1083394560।)


के रूप में क्यों floatपरिवर्तित करने के लिए double, के रूप में printf के प्रोटोटाइप है int printf(const char*, ...), 6.5.2.2/7 से,

एक फ़ंक्शन प्रोटोटाइप घोषणाकर्ता में एलिप्सिस नोटेशन अंतिम घोषित पैरामीटर के बाद तर्क प्रकार रूपांतरण को रोकने का कारण बनता है। डिफ़ॉल्ट तर्क पदोन्नति अनुगामी तर्कों पर किया जाता है।

और 6.5.2.2/6 से,

यदि अभिव्यक्ति जो फ़ंक्शन को सूचित करती है, उसमें एक प्रकार होता है जिसमें एक प्रोटोटाइप शामिल नहीं होता है, तो प्रत्येक तर्क पर पूर्णांक प्रचार किया जाता है, और प्रकार वाले तर्क floatको बढ़ावा दिया जाता है doubleइन्हें डिफ़ॉल्ट तर्क पदोन्नति कहा जाता है ।

(यह जानने के लिए आलोक का धन्यवाद।)


4
+1 उत्तम उत्तर। यह दोनों "मानक तकनीकी रूप से सही" क्यों और "आपकी संभावना कार्यान्वयन" क्यों का उत्तर देता है।
क्रिस लुत्ज

12
मेरा मानना ​​है कि आप केवल 12 लोगों में से एक हैं जो वास्तव में वह उत्तर प्रदान करते हैं जिसकी उन्हें तलाश थी।
गाबे

11
क्योंकि printfएक वैरिएडिक फ़ंक्शन है, और मानक कहता है कि वैराडिक फ़ंक्शन के लिए, ए पास होने floatसे doubleपहले परिवर्तित हो जाता है ।
आलोक सिंघल

8
C मानक से: "एक फ़ंक्शन प्रोटोटाइप घोषणाकर्ता में दीर्घवृत्त संकेतन अंतिम अंतिम पैरामीटर के बाद रुकने के लिए तर्क प्रकार रूपांतरण का कारण बनता है। डिफ़ॉल्ट तर्क पदोन्नति अनुगामी तर्कों पर किया जाता है।" और "... और तर्क जो फ्लोट टाइप करते हैं, उन्हें डबल में पदोन्नत किया जाता है। इन्हें डिफ़ॉल्ट तर्क पदोन्नति कहा जाता है ।"
आलोक सिंघल

2
में गलत स्वरूप विनिर्देशक का उपयोग करते हुए printf()आह्वान अपरिभाषित व्यवहार
प्रसून सौरव

45

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

उदाहरण के लिए, मेरी मैकबुक पर, मुझे 1606416304आपके प्रोग्राम के साथ आउटपुट मिलता है ।

यह कहने के बाद कि, जब आप floatकिसी वैरिएड फ़ंक्शन को पास करते हैं, तो floatइसे ए के रूप में पास किया जाता है double। तो, आपका कार्यक्रम aएक के रूप में घोषित होने के बराबर है double

A के बाइट्स की जांच करने के लिए double, आप एसओ पर यहां एक हालिया प्रश्न का उत्तर देख सकते हैं ।

चलो करते हैं:

#include <stdio.h>

int main(void)
{
    double a = 1234.5f;
    unsigned char *p = (unsigned char *)&a;
    size_t i;

    printf("size of double: %zu, int: %zu\n", sizeof(double), sizeof(int));
    for (i=0; i < sizeof a; ++i)
        printf("%02x ", p[i]);
    putchar('\n');
    return 0;
}

जब मैं उपरोक्त कार्यक्रम चलाता हूं, मुझे मिलता है:

size of double: 8, int: 4
00 00 00 00 00 4a 93 40 

तो, पहले चार बाइट्स double0 निकले, जो हो सकता है कि आपको 0अपने printfकॉल के आउटपुट के रूप में मिले ।

अधिक रोचक परिणामों के लिए, हम कार्यक्रम को थोड़ा बदल सकते हैं:

#include <stdio.h>

int main(void)
{
    double a = 1234.5f;
    int b = 42;

    printf("%d %d\n", a, b);
    return 0;
}

जब मैं अपनी मैकबुक पर उपरोक्त कार्यक्रम चलाता हूं, तो मुझे यह मिलता है:

42 1606416384

लिनक्स मशीन पर एक ही कार्यक्रम के साथ, मुझे यह मिलता है:

0 1083394560

आपने प्रोग्राम का प्रिंट बैकवर्ड क्यों किया? क्या मैं कुछ भूल रहा हूँ? यदि b एक int = 42 है, और '% d' पूर्णांक स्वरूप है, तो यह दूसरा मुद्रित मूल्य क्यों नहीं है, क्योंकि यह प्रिंटफ तर्क में दूसरा चर है? क्या यह एक टाइपो है?
कटस्टिक यात्रा

शायद इसलिए कि intतर्कों की तुलना में विभिन्न रजिस्टरों में तर्क पारित किए जाते हैं doubleprintfसाथ %dले जाता है intतर्क है कि 42 है और दूसरा %dशायद कबाड़ प्रिंट के बाद से वहाँ एक दूसरे नहीं था intतर्क।
आलोक सिंघल

20

%dविनिर्देशक बताता है printfएक पूर्णांक अपेक्षा करनी चाहिए। तो पहले चार (या दो, प्लेटफ़ॉर्म पर निर्भर करता है) फ्लोट के बाइट्स को पूर्णांक के रूप में रखा जाता है। यदि वे शून्य होते हैं, तो एक शून्य मुद्रित होता है

1234.5 का द्विआधारी प्रतिनिधित्व कुछ ऐसा है

1.00110100101 * 2^10 (exponent is decimal ...)

एक सी संकलक के साथ जो floatवास्तव में IEEE754 दोहरे मूल्यों के रूप में प्रतिनिधित्व करता है, बाइट्स होगा (अगर मैंने कोई गलती नहीं की)

01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000

एक इंटेल (x86) सिस्टम पर थोड़ा एंडियनस (यानी सबसे कम महत्वपूर्ण बाइट पहले आ रहा है) के साथ, यह बाइट अनुक्रम उल्टा हो जाता है ताकि पहले चार बाइट शून्य हो। यही है, क्या printfप्रिंट बाहर ...

IEEE754 के अनुसार फ्लोटिंग पॉइंट प्रतिनिधित्व के लिए यह विकिपीडिया लेख देखें ।


7

यह बाइनरी में एक फ्लोट के प्रतिनिधित्व के कारण है। पूर्णांक में रूपांतरण इसे 0 से छोड़ता है।


1
आपको लगता है कि केवल वही समझ रहा था जो वह पूछ रहा था। जब तक इम ने खुद को गलत नहीं समझा।
मिज़िपज़ोर

मैं मानता हूं कि उत्तर गलत और अधूरा है, लेकिन गलत नहीं है।
शाही

7

क्योंकि आपने अपरिभाषित व्यवहार का आह्वान किया था: आपने इसके पैरामीटर प्रकारों के बारे में झूठ बोलकर प्रिंटफ () पद्धति के अनुबंध का उल्लंघन किया था, इसलिए संकलक जो कुछ भी करना चाहता है करने के लिए स्वतंत्र है। यह कार्यक्रम का उत्पादन कर सकता है "dksjalk एक निन्नीहेड है !!!" और तकनीकी रूप से यह अभी भी सही होगा।


5

कारण यह है कि printf()एक सुंदर गूंगा कार्य है। यह सभी प्रकार की जाँच नहीं करता है। यदि आप कहते हैं कि पहला तर्क एक है int(और यह आप जो कह रहे हैं %d), यह आपको विश्वास करता है और यह सिर्फ एक के लिए आवश्यक बाइट्स लेता है int। इस मामले में, मान लें कि आपकी मशीन चार-बाइट intऔर आठ-बाइट का उपयोग करती है double(इसे अंदर floatमें बदल दिया जाता है ), पहले चार बाइट्स केवल शून्य होंगे, और यह प्रिंट हो जाता है।doubleprintf()a


3

यह स्वतः पूर्णांक में नहीं बदलेगा। क्योंकि दोनों में स्टोरेज का अलग प्रारूप है। इसलिए यदि आप कनवर्ट करना चाहते हैं, तो (int) टाइपकास्टिंग का उपयोग करें।

#include <stdio.h>

int main() {
    float a = 1234.5f;
    printf("%d\n", (int)a);
    return 0;
}

2

चूंकि आपने इसे C ++ के साथ टैग किया था, इसलिए यह कोड वैसा ही रूपांतरण करता है जैसा आप शायद उम्मीद करते हैं:

#include <iostream.h>

int main() {
    float a = 1234.5f;
    std::cout << a << " " << (int)a << "\n";
    return 0;
}

आउटपुट:

1234.5 1234

1

%d दशमलव है

%f तैर रहा है

इनमें से अधिक यहाँ देखें

आप 0 प्राप्त कर रहे हैं क्योंकि फ़्लोट्स और पूर्णांक अलग-अलग प्रतिनिधित्व करते हैं।


1

आपको बस प्रासंगिक डेटा प्रकार (इंट, फ्लोट, स्ट्रिंग, आदि) के साथ उचित प्रारूप विनिर्देशक (% d,% f,% s, आदि) का उपयोग करने की आवश्यकता है।


सवाल यह नहीं है कि इसे कैसे ठीक किया जाए बल्कि यह जिस तरह से काम करता है उसी तरह से काम करता है।
यंहा ०


0

अरे यह कुछ मुद्रित करने के लिए किया था तो यह एक छ 0 मुद्रित किया था। C 0 में याद रखें बाकी सब कुछ है!


1
ऐसा कैसे है? C में हर चीज जैसी कोई चीज नहीं है।
व्लाद

यदि x कुछ है, तो! x == 0 :)
chunkyguy

अगर (iGot == "सब कुछ") "सब कुछ" प्रिंट करें ; और प्रिंट "कुछ भी नहीं";
निक

0

यह पूर्णांक नहीं है। प्रयोग करके देखें %f


मुझे लगता है कि सवाल यह है कि यह फ्लोट को सिर्फ int और "1234" को प्रदर्शित करने के लिए परिवर्तित क्यों नहीं करता है?
ब्योर्न पोलेक्स

उम्मीद न करें कि आप ऐसा कुछ नहीं करेंगे जिससे कोई तार्किक समझ न आए। हां कई भाषाएं 1234 दे सकती हैं जिनकी आप उम्मीद कर सकते हैं, और शायद सी के कुछ कार्यान्वयन भी मुझे नहीं लगेगा कि यह व्यवहार परिभाषित है। C आपको अपने माता-पिता की तरह अपने आप को लटका देता है जो आपको इसके नरक के लिए दरार का प्रयास करने देता है।
un:

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