printf

2010-03-11 5 views
9

मैं इस छोटे से कोड लिखा है:printf

#include <stdio.h> 
int main() { 
    size_t temp; 
    temp = 100; 

    printf("lld=%lld, ld=%ld, u=%u\n", temp, temp, temp); 

    return 0; 
} 

मैं जीसीसी संस्करण के साथ एक i386 जीएनयू/लिनक्स मशीन पर यह चल रहा 4.1.1 20,070,105 (रेड हैट 4.1.1-52)

lld=429496729700, ld=100, u=7993461 

मैं समझ सकता है कि पहले (lld) कचरा के रूप में मुद्रित किया गया था क्योंकि printf की कोशिश करता है (जैसा कि lld द्वारा संकेतित signed long long के लिए) 8 बाइट्स मुद्रित करने के लिए जब केवल 4 बाइट उपलब्ध हैं: यह आउटपुट है कि मुझे मिल गया है परिवर्तनीय temp से। लेकिन, मैं समझने में असफल रहा कि अंतिम पहचानकर्ता, u कचरा के रूप में मुद्रित क्यों हो रहा है - जबकि, मेरी समझ में यह size_t के लिए निकटतम लागू पहचानकर्ता है।

यहां मैंने माना है कि size_tunsigned int है (जो मेरे i386 के लिए 4 बाइट्स पर हस्ताक्षर है)।

अब, मैं printf लाइन के साथ एक छोटे से फेरबदल किया:

... 
printf("ld=%ld, u=%u, lld=%lld\n", temp, temp, temp); 
... 

और मैं एक बिल्कुल ठीक जवाब (lld भाग को छोड़कर)।

ld=100, u=100, lld=34331653576851556 

क्या कोई मुझे समझने में मेरी सहायता कर सकता है कि मैं वास्तव में क्या खो रहा हूं?

किसी भी मदद के लिए बहुत बहुत धन्यवाद!

[ओर ध्यान दें: मैं अवलोकन में कोई अंतर के बिना/बंद gcc -O[0,2] टैग का उपयोग कर अनुकूलन स्विचन की कोशिश की।]

+0

द -फॉर्मैट विकल्प शायद आपके लिए इस असंगतता का पता लगाएगा। – Clifford

+0

@Clifford इनपुट के लिए धन्यवाद - लेकिन, मैं जानबूझ कर गलत विनिर्देशकों का उपयोग कर रहा था। मैं वास्तव में जानना चाहता था कि कैसे 'printf' ढेर पर तत्वों का उपभोग कर रहा था। असल में, मुझे लगता है -Wall भी वही बात होगी। फिर भी, बहुत बहुत धन्यवाद। – Shrey

+0

मुझे एहसास हुआ कि यह जानबूझकर था; लेकिन मेरा मुद्दा यह था कि यदि इरादा संकलक के व्यवहार का पालन करना था, तो -फॉर्मैट विकल्प वैकल्पिक (और सुरक्षित) व्यवहार का प्रदर्शन करता है, जो किसी के लिए ब्याज का हो सकता है, भले ही आप पहले से ही इसके बारे में जानते हों। -वॉल में शामिल नहीं था - जीसीसी के पुराने संस्करणों पर वर्फैट। – Clifford

उत्तर

22

ऐसा इसलिए है क्योंकि तुम क्या ढेर पर धकेल दिया गया है तीन 32-बिट मूल्यों और है आपके प्रारूप स्ट्रिंग उनमें से चार का उपयोग करने की कोशिश करता है, या अधिक सटीक रूप से, एक 64-बिट मान और दो 32-बिट मान।

पहले मामले में, lld दो 32-बिट मान बेकार है, ld तीसरा ऊपर बेकार है और u जो कुछ उस के बाद ढेर, जो वास्तव में कुछ भी हो सकता पर होने वाला हो जाता है।

जब आप स्ट्रिंग में प्रारूप विनिर्देशक का क्रम बदलने, इसे दूसरे तरीके से क्योंकि ld पहले 32-बिट मूल्य को बेकार काम करता है, u सेकंड बेकार है और lld तीसरे प्लस जो कुछ भी होता है ऊपर बेकार उसके बाद ढेर पर होना। यही कारण है कि आप अलग-अलग मान प्राप्त कर रहे हैं, यह डेटा संरेखण/उपलब्धता समस्या है।

आप इसे पहले मान के साथ कार्रवाई में देख सकते हैं। 42 9 4 9 6729700 (4294967296 + 1) * 100 के बराबर है, यानी, (2 +1) * 100।

What you pass  Stack  What printf() uses 
-------------  -----  ------------------ 
       +-----+ 
100    | 100 | \ 
       +-----+ = 64-bit value for %lld. 
100    | 100 |/
       +-----+ 
100    | 100 | 32-bit value for %ld. 
       +-----+ 
       | ? | 32-bit value for %u (could be anything). 
       +-----+ 

दूसरे मामले में

printf("ld=%ld, u=%u, lld=%lld\n", temp, temp, temp); 

निम्नलिखित होता है::

What you pass  Stack  What printf() uses 
-------------  -----  ------------------ 
       +-----+ 
100    | 100 | 32-bit value for %ld. 
       +-----+ 
100    | 100 | 32-bit value for %u. 
       +-----+ 
100    | 100 | \ 
       +-----+ = 64-bit value for %lld (could be anything). 
       | ? |/
       +-----+ 
+0

यूप, यह पूरी तरह उत्तर देने के लिए लगता है कि मैं देख रहा था। मैंने असेंबली कोड के माध्यम से पढ़ा है और यह भी आपके द्वारा उल्लेख किया गया है (स्टैक पर 32 बाइट के 3 चर को धक्का देने का हिस्सा)। मैं बस पुष्टि नहीं कर सका कि printf उन्हें कैसे खा रहा था। पुष्टि करने के लिए धन्यवाद! – Shrey

0

आप printf करने से गुजर रहे हैं आपका कोड स्निपेट

printf("lld=%lld, ld=%ld, u=%u\n", temp, temp, temp); 

वास्तव में निम्नलिखित प्रभाव पड़ता है बी की गलत संख्या ytes। % lld को एक बड़ा पूर्णांक की आवश्यकता होती है, आपके मामले में जिस तरह से% lld अपना तर्क लेता है पूरी तरह से गड़बड़ हो जाता है, क्योंकि यह 64-बिट मान की अपेक्षा करता है।

7

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

printf("lld=%lld, ld=%ld, u=%u\n", 
     (unsigned long long)temp, 
     (unsigned long)temp, 
     (unsigned int)temp); 

के रूप में एक अलग रूप में विनिर्देशक याद size_tz है के लिए। तो:

printf("zd=%zd\n", temp);