2012-11-08 3 views
6

(86, 32 या 64 बिट के लिए) इस उदाहरणसी ++ मानक ऐसी संरचनाओं संरेखित करने के लिए में यह है

class A 
{ 
public: 
    int a; 
    char b; 
    int c; 
}; 

हर संकलक ले लो मैं देख रहा हूँ वर्ग A के लिए 12 बाइट्स आबंटित करता है, 9. के बजाय तो वे संरेखित कर रहे हैं b पूर्णांक सीमा या बस सीमा तक आप कह सकते हैं। मेरा सवाल यह है कि यदि ऐसा करने के लिए यह सी ++ मानक में है और यदि कोई ऐसे कंपाइलर हैं जो ऐसा नहीं करते हैं।

उत्तर

15

सी ++ मानक यह बताता है कि:

  • वस्तुओं एक संरेखण आवश्यकता उनके आकार एक से अधिक है, जिनमें से है (इसलिए यदि int 4 बाइट व्यापक है, तो यह 1, 2 या 4 बाइट्स की एक संरेखण की आवश्यकता है, कार्यान्वयन के आधार पर)।
  • सदस्य ऑब्जेक्ट्स (यदि वे public जैसे एक्सेस विनिर्देशकों द्वारा अलग नहीं हैं) वे सभी को
  • घोषित किए गए क्रम में आवंटित किए गए हैं और उन्हें उनके संरेखण आवश्यकताओं का सम्मान करने के लिए आवंटित किया गया है।

तो नहीं, मानक यह नहीं कहता कि कक्षा में 12 बाइट्स का आकार होना चाहिए।

लेकिन यह का कहना है कि ba के बाद आवंटित किया जाना चाहिए, और कहा कि cb के बाद आवंटित किया जाना चाहिए है।

  • a पहले 4 बाइट्स
  • b एक बाइट लेता है लेता है:

    एक मंच जहां int 4 बाइट व्यापक है, और 4 बाइट संरेखण की आवश्यकता है, यह सबसे छोटी मान्य आकार के रूप में 12 बाइट्स छोड़ देता है

  • c को 4 बाइट्स, की आवश्यकता है लेकिन को 4-बाइट सीमा पर आवंटित किया जाना चाहिए।b, एक बाइट पिछले इस तरह के एक सीमा समाप्त हो गया तो अगले वैध स्थिति में गद्दी के 3 बाइट्स डालने से पाया जाता है c जगह।

तो वर्ग का कुल आकार, सदस्य (4 + 1 + 4 = 9) के अलावा तीन गद्दी के बाइट्स के आकार जा रहा है 12.

के लिए कुल एक और नियम है समाप्त होता है जिसका यहां कोई प्रभाव नहीं पड़ता है, लेकिन इससे कोई फर्क नहीं पड़ता कि आपने सदस्यों को a, c, b क्रम में परिभाषित किया था।

युक्त वर्ग (A) कठोरतम गठबंधन सदस्य वस्तु से संरेखण आवश्यकता इनहेरिट करती है। यही है, क्योंकि यह एक int होता है, यह एक ही संरेखण आवश्यकता एक int करता है के रूप में है। और क्योंकि वस्तु के कुल आकार अपने संरेखण आवश्यकता का गुणांक होना चाहिए, एक वर्ग के क्रम में सदस्यों युक्त a, b, c होगा अभी भी भंडारण के 12 बाइट्स की आवश्यकता है। यह केवल b और c के बीच कक्षा के अंत तक पैडिंग के 3 बाइट्स को स्थानांतरित करेगा।

हालांकि, कुछ अन्य मामलों में, आकार के अवरोही क्रम में सदस्यों को पुन: व्यवस्थित करने से कभी-कभी कक्षा के आकार को कम कर सकता है।

मान लीजिए हम बजाय इस तरह एक वर्ग था था:

class B { 
    char a; 
    double b; 
    int c; 
}; 

यह भंडारण के 24 बाइट्स (1 a के लिए बाइट्स, b के लिए 8 बाइट, और c के लिए 4 बाइट की आवश्यकता रही होगी, लेकिन तब के लिए सुनिश्चित करें कि b 8-बाइट सीमा पर समाप्त होता है, हमें a और b के बीच पैडिंग के बाइट्स की आवश्यकता होगी, और यह सुनिश्चित करने के लिए कि पूरी कक्षा 8 के एक से अधिक आकार के साथ समाप्त हो, हमें एक और 4 बाइट की आवश्यकता है c के बाद

लेकिन आकार के अनुसार सदस्यों को पुन: क्रम, इस तरह: एक कक्षा में

class B { 
    double b; 
    int c; 
    char a; 
}; 

परिणाम केवल 16 बाइट्स की आवश्यकता होती है:

ही 1 + 4 + 8 बाइट्स सदस्य खुद को वस्तुओं के लिए, लेकिन अब c पहले से ही एक 4-बाइट सीमा पर गठबंधन है, और a किसी भी संरेखण कभी नहीं की जरूरत है, इसलिए केवल संरेखण हम की जरूरत है सुनिश्चित करने के लिए B एक आकार है कि एक से अधिक है कि है (क्योंकि यह b जो एक 8 बाइट सीमा को समाप्त होता है के बाद है) 8 में से सदस्य 13 बाइट लेते हैं, इसलिए हम पैडिंग के 3 बाइट जोड़ सकते हैं, और कक्षा 16 बाइट्स पर समाप्त होती है, 33% छोटी थी एन पहला संस्करण।

+1

आप यह भी बता सकते हैं कि अधिकांश आर्किटेक्चर पर, गलत गठबंधन ऑब्जेक्ट तक पहुंचने से कुछ प्रकार की बस त्रुटि हो जाएगी, जिससे प्रोग्राम क्रैश हो जाएगा। इंटेल पर, प्रोग्राम क्रैश नहीं होगा, लेकिन डेटा गलत तरीके से होने पर यह अभी भी धीमा हो जाएगा। –

0

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

1

प्रज्ञा निर्देशों का उपयोग करके संकलन-समय पर संरचना पैकिंग को नियंत्रित करना संभव है। See #Pragma Pack

उदाहरण के लिए, निम्नलिखित सदस्यों संरेखित नहीं करता है, और उन्हें एक दूसरे के ठीक बगल देता है।

#pragma pack(push, 1) 
struct A4 
{ 
    char a; 
    double b; 
    char c; 
}; 
#pragma pack(pop) 

से here उदाहरण।

GCC भी प्रगा पैक का समर्थन करता है। निर्देश कुछ मानक का हिस्सा नहीं है, लेकिन बहुत से कंपाइलर्स इसका समर्थन करते हैं।


हालांकि, उपर्युक्त करने का कोई कारण नहीं होना चाहिए। कंपाइलर उन्हें सदस्यों तक पहुंच बढ़ाने के लिए संरेखित करता है, और को बदलने का कोई कारण नहीं होना चाहिए।

+0

'pragma pack' पोर्टेबल है? क्या यह अन्य कंपाइलर्स काम करता है? –

+0

लेकिन क्या यह सी ++ मानक में परिभाषित किया गया है कि डिफ़ॉल्ट स्थिति बस सीमा पर संरेखित करना होगा। – pythonic

+0

@AlessandroPezzato: http://stackoverflow.com/a/13267797/76722 –

0

हां, मानक में मुख्य रूप से खंड 3.11 (संरेखण) संरेखण का उल्लेख किया गया है। यह मंच-निर्भर है, इसलिए किसी भी प्रोग्राम जो किसी ऑब्जेक्ट के वास्तविक आकार पर निर्भर करता है वह स्वाभाविक रूप से गैर-पोर्टेबल है।

0

आपके मामले में 'बी' हमेशा सही ढंग से गठबंधन होता है। यह गद्देदार 32-बिट सीमाओं में संरेखित करने के लिए है। भले ही विशिष्ट कार्यान्वयन के लिए कुछ जगह है, अधिकांश कंपाइलर 2 और 4 बाइट चर के लिए 2 और 4-बाइट चर संरेखित करने के नियम का पालन करते हैं।

32-बिट सिस्टम में भी युगल और लंबे इट्स (8 बाइट्स) 4-बाइट सीमाओं के साथ गठबंधन होते हैं, लेकिन 64-बिट सिस्टम में 8-बाइट से गठबंधन होते हैं।

+0

सिस्टम विभिन्न प्रकारों को संरेखित कैसे करते हैं, यह बहुत ही कार्यान्वयन निर्भर है। मैंने 32 बिट सिस्टम का उपयोग किया है जहां 8 बाइट सीमाओं पर युगल गठबंधन किए गए थे, और मैंने 'लंबे डबल' के लिए सभी प्रकार के संरेखण देखा है। –

+0

वैसे हाँ, हो सकता है कि लंबी डबल संगतता की सीमा को दबा रहा हो। –

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