कुछ मशीनों पर एक लंबा int 12 बाइट्स क्यों लेता है?


26

मैंने अपने मशीन पर इस कोड को संकलित करने के बाद कुछ अजीब देखा:

#include <stdio.h>

int main()
{
    printf("Hello, World!\n");

    int a,b,c,d;

    int e,f,g;

    long int h;

    printf("The addresses are:\n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x \n %0x",
        &a,&b,&c,&d,&e,&f,&g,&h);

    return 0;
}

परिणाम निम्नलिखित है। ध्यान दें कि प्रत्येक अंतर पते के बीच 4-बाइट अंतर है। हालांकि, अंतिम अंतर और लंबे अंतर के बीच 12-बाइट अंतर है:

 Hello, World!
 The addresses are:

 da54dcac 
 da54dca8 
 da54dca4 
 da54dca0 
 da54dc9c 
 da54dc98 
 da54dc94 
 da54dc88

3
सोर्स कोड के intबाद दूसरा लगाएं h। संकलक इसे पहले, अंतराल में डाल सकता है h
सीटीएल-अल्ट-डेलोर

32
आकार निर्धारित करने के लिए मेमोरी पतों के बीच के अंतर का उपयोग न करें। उसके sizeofलिए एक फंक्शन है। printf("size: %d ", sizeof(long));
क्रिस श्नाइडर

10
आप केवल अपने पते के कम 4 बाइट्स के साथ मुद्रित कर रहे हैं %x। आपके लिए भाग्यशाली है, यह आपके प्लेटफ़ॉर्म पर सही ढंग से काम करने के लिए होता है, जो सूचक स्ट्रिंग की अपेक्षा करता है unsigned int। लेकिन कई एबीआई में पॉइंटर्स और इनट्स अलग-अलग आकार के होते हैं। %pपोर्टेबल कोड में पॉइंटर्स प्रिंट करने के लिए उपयोग करें । (ऐसी प्रणाली की कल्पना करना आसान है जहां आपका कोड पहले 4 पॉइंटर्स के ऊपरी / निचले हिस्सों को प्रिंट करेगा, सभी के निचले आधे के बजाय 8.)
पीटर कॉर्ड्स


2
@ लल्लू गलत सूचना नहीं फैलाता। कोई भी सभ्य संकलक उस क्रम के बारे में परवाह नहीं करता है जिसमें सी में चर घोषित किए जाते हैं। अगर यह परवाह करता है, तो कोई कारण नहीं है कि यह आपके द्वारा वर्णित तरीके को पूरा करेगा।
gnasher729

जवाबों:


81

यह 12 बाइट्स नहीं लेता था, इसमें केवल 8. लिया गया था। हालांकि, इस प्लेटफॉर्म पर 8 बाइट्स के लिए डिफ़ॉल्ट संरेखण 8 बाइट्स है। इस प्रकार, कंपाइलर को 8 से विभाज्य पते के लिए लंबे इंट को स्थानांतरित करने की आवश्यकता है। "स्पष्ट" पता, da54dc8c, 8 से विभाज्य नहीं है इसलिए 12 बाइट का अंतर है।

आपको इसका परीक्षण करने में सक्षम होना चाहिए। यदि आप लंबे समय से पहले एक और int जोड़ते हैं, तो उनमें से 8 हैं, तो आपको यह पता लगाना चाहिए कि लंबे int को बिना किसी चाल के ठीक किया जाएगा। अब यह पिछले पते से केवल 8 बाइट्स होगा।

यह संभवतः इंगित करने के लायक है कि, हालांकि यह परीक्षण काम करना चाहिए, आपको इस तरह से आयोजित किए जा रहे चर पर भरोसा नहीं करना चाहिए। एसी कंपाइलर को आपके प्रोग्राम को फिर से ऑर्डर करने वाले वेरिएबल्स (कुछ कैविटी के साथ) सहित जल्दी से चलाने की कोशिश करने के लिए हर तरह की फंकी चीजें करने की अनुमति है।


3
अंतर, अंतर नहीं।
Deduplicator

10
"वैरिएबल री-ऑर्डर करने सहित"। यदि संकलक यह तय करता है कि आप एक ही समय में दो चर का उपयोग नहीं करते हैं, तो यह आंशिक रूप से ओवरलैप करने या उन्हें पूरी तरह से ओवरले करने के लिए स्वतंत्र है ...
रोजर लिप्सकॉम्ब

8
या वास्तव में, उन्हें स्टैक के बजाय रजिस्टरों में रखें।
मोनिका

11
@OrangeDog मुझे नहीं लगता कि अगर इस मामले में पता चला है तो क्या होगा लेकिन, सामान्य तौर पर, आप निश्चित रूप से सही हैं।
एलेक्स

5
@ एलेक्स: एड्रेस लेते समय आप मेमोरी और रजिस्टर के साथ मज़ेदार चीज़ें प्राप्त कर सकते हैं। एड्रेस लेने का मतलब है कि इसे मेमोरी लोकेशन देना है, लेकिन इसका मतलब यह नहीं है कि इसका वास्तव में उपयोग करना है। यदि आप पता लेते हैं, तो इसे 3 असाइन करें और इसे किसी अन्य फ़ंक्शन को पास करें, यह सिर्फ RDI में 3 लिख सकता है और कॉल कर सकता है, इसे मेमोरी में कभी नहीं लिख सकता है। कभी-कभी एक डिबगर में आश्चर्य।
ज़ैन लिंक्स

9

ऐसा इसलिए है क्योंकि आपका कंपाइलर चर के बीच अतिरिक्त पैडिंग पैदा कर रहा है ताकि यह सुनिश्चित हो सके कि वे मेमोरी में सही तरीके से संरेखित हैं।

अधिकांश आधुनिक प्रोसेसर पर, यदि किसी मान में एक पता है जो उसके आकार का एक गुण है, तो इसे एक्सेस करना अधिक कुशल है। यदि यह hपहले उपलब्ध स्थान पर लगा होता, तो इसका पता 0xda54dc8c होता, जो 8 का गुणक नहीं है, इसलिए उपयोग करने में कम कुशल होता। कंपाइलर इसके बारे में जानता है और यह सुनिश्चित करने के लिए आपके पिछले दो चर के बीच अप्रयुक्त स्थान को थोड़ा जोड़ रहा है ताकि यह सुनिश्चित हो सके।


स्पष्टीकरण के लिए धन्यवाद। क्या आप मुझे कुछ सामग्रियों के बारे में बता सकते हैं, जिनके कारण उन वैरिएबल तक पहुंचना, जो उनके आकार के कई हैं, अधिक कुशल हैं? मैं जानना चाहूंगा कि ऐसा क्यों हो रहा है?
yoyo_fun

4
@yoyo_fun और यदि आप वास्तव में स्मृति को समझना चाहते हैं, तो इस विषय पर एक प्रसिद्ध शोधपत्र है। FutureCl.blinkenlights.nl/misc/cpumemory.pdf
एलेक्स

1
@yoyo_fun यह काफी सरल है। कुछ मेमोरी कंट्रोलर केवल प्रोसेसर की बिट चौड़ाई के गुणकों तक पहुँच सकते हैं (उदाहरण के लिए एक 32-बिट प्रोसेसर केवल 0-3, 4-7, 8-11, आदि के लिए सीधे अनुरोध कर सकते हैं)। यदि आप गैर-संरेखित पते के लिए पूछते हैं, तो प्रोसेसर को दो मेमोरी अनुरोध करना पड़ता है फिर डेटा को रजिस्टर में प्राप्त करें। तो, वापस 32-बिट पर, यदि आप पते 1 पर संग्रहीत मान चाहते थे, तो प्रोसेसर को 0-3, 4-7 पते के लिए पूछना होगा, फिर 1, 2, 3 और 4 के बाइट्स से बाइट्स प्राप्त करें। याददाश्त बर्बाद हो गई।
फेयरफॉक्स

2
माइनर पॉइंट, लेकिन गलत तरीके से की गई मेमोरी एक्सेस एक परफॉर्मेंस हिट के बजाय एक अपरिवर्तनीय गलती हो सकती है। वास्तुकला पर निर्भर है।
जॉन चेस्टरफील्ड

1
@JonChesterfield - हाँ। इसलिए मैंने टिप्पणी की कि मैंने जो विवरण दिया वह अधिकांश आधुनिक आर्किटेक्चर पर लागू होता है (जिसके द्वारा मेरा मतलब x86 और ARM से था)। ऐसे अन्य हैं जो अलग-अलग तरीकों से व्यवहार करते हैं, लेकिन वे काफी कम आम हैं। : (दिलचस्प एआरएम इस्तेमाल किया आर्किटेक्चर पहुँच गठबंधन की आवश्यकता में से एक है, लेकिन वे बाद के संशोधनों में असंरेखित पहुंच का स्वत: हैंडलिंग जोड़ा)
जूल्स

2

आपका परीक्षण आवश्यक रूप से परीक्षण नहीं करता है कि आप क्या सोचते हैं, क्योंकि भाषा की कोई आवश्यकता नहीं है कि इनमें से किसी भी स्थानीय चर का पता एक-दूसरे से संबंधित हो।

भंडारण के आवंटन के बारे में कुछ अनुमान लगाने में सक्षम होने के लिए आपको इन्हें एक संरचना में फ़ील्ड के रूप में रखना होगा।

स्थानीय चर को किसी विशेष तरीके से एक दूसरे के बगल में भंडारण साझा करने की आवश्यकता नहीं होती है। कंपाइलर, स्टैक के भीतर कहीं भी एक अस्थायी चर डाल सकता है, उदाहरण के लिए, जो इनमें से किसी भी दो स्थानीय चर के बीच हो सकता है।

इसके विपरीत, इसे एक अस्थायी चर को एक संरचना में सम्मिलित करने की अनुमति नहीं दी जाएगी, इसलिए यदि आप इसके बजाय संरचना क्षेत्रों के पते मुद्रित करते हैं, तो आप स्मृति के समान तार्किक चक (संरचना) से आवंटित वस्तुओं की तुलना करेंगे।

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