c++ - प्रत्येक सदस्य के आकार के बराबर संरचना के लिए आकार क्यों नहीं है?




struct sizeof (8)

अन्य उत्तरों के अलावा, एक संरचना (लेकिन आमतौर पर नहीं) वर्चुअल फ़ंक्शंस कर सकती है, इस स्थिति में संरचना के आकार में vtbl के लिए स्थान भी शामिल होगा।

'आकार' ऑपरेटर संरचना के सदस्यों के कुल आकार की तुलना में संरचना के लिए आकार बड़ा क्यों करता है?


एक संरचना का आकार अपने भागों के योग से अधिक है क्योंकि पैकिंग कहा जाता है। एक विशेष प्रोसेसर के पास एक पसंदीदा डेटा आकार होता है जो इसके साथ काम करता है। 32-बिट्स (4 बाइट्स) के दौरान अधिकांश आधुनिक प्रोसेसर का पसंदीदा आकार। जब इस तरह की सीमा पर डेटा होता है तो स्मृति तक पहुंचने से उस आकार की सीमा से अधिक कुशलता होती है।

उदाहरण के लिए। सरल संरचना पर विचार करें:

struct myStruct
{
   int a;
   char b;
   int c;
} data;

यदि मशीन 32-बिट मशीन है और 32-बिट सीमा पर डेटा गठबंधन किया गया है, तो हमें तत्काल समस्या दिखाई दे रही है (कोई संरचना संरेखण नहीं माना जाता है)। इस उदाहरण में, आइए मान लें कि संरचना डेटा 1024 (0x400 - पता है कि सबसे कम 2 बिट शून्य हैं, इसलिए डेटा 32-बिट सीमा से गठबंधन है)। Data.a तक पहुंच ठीक काम करेगी क्योंकि यह सीमा पर शुरू होती है - 0x400। Data.b तक पहुंच भी ठीक काम करेगी, क्योंकि यह पता 0x404 - एक और 32-बिट सीमा है। लेकिन एक unaligned संरचना पता 0x405 पर data.c डाल देगा। Data.c के 4 बाइट 0x405, 0x406, 0x407, 0x408 पर हैं। 32-बिट मशीन पर, सिस्टम एक स्मृति चक्र के दौरान data.c पढ़ेगा, लेकिन केवल 4 बाइट्स में से 3 प्राप्त होगा (चौथा बाइट अगली सीमा पर है)। इसलिए, 4 वें बाइट प्राप्त करने के लिए सिस्टम को दूसरी मेमोरी एक्सेस करना होगा,

अब, अगर 0x405 पते पर data.c डालने की बजाय, कंपाइलर ने संरचना को 3 बाइट्स से पैड किया है और पता 0x408 पर डेटा.c डाल दिया है, तो सिस्टम को डेटा को पढ़ने के लिए केवल 1 चक्र की आवश्यकता होगी, उस डेटा तत्व में एक्सेस टाइम काटने 50% तक। प्रसंस्करण दक्षता के लिए पैडिंग स्मृति दक्षता स्वैप। यह देखते हुए कि कंप्यूटर में बड़ी मात्रा में मेमोरी (कई गीगाबाइट्स) हो सकते हैं, कंपेलरों का मानना ​​है कि स्वैप (आकार पर गति) एक उचित है।

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

दूसरी ओर, डेटा संरचना पैकिंग को प्रबंधित करने के लिए विभिन्न कंपाइलर्स की अलग-अलग क्षमताएं होती हैं। उदाहरण के लिए, विजुअल सी / सी ++ में कंपाइलर #pragma पैक कमांड का समर्थन करता है। यह आपको डेटा पैकिंग और संरेखण समायोजित करने की अनुमति देगा।

उदाहरण के लिए:

#pragma pack 1
struct MyStruct
{
    int a;
    char b;
    int c;
    short d;
} myData;

I = sizeof(myData);

अब मेरे पास 11 की लंबाई होनी चाहिए। प्रज्ञा के बिना, मैं कंपाइलर के डिफ़ॉल्ट पैकिंग के आधार पर 11 से 14 (और कुछ प्रणालियों के लिए, 32 तक) कुछ भी हो सकता था।


पैकिंग और बाइट संरेखण, जैसा here सी एफएक्यू में वर्णित here :

यह संरेखण के लिए है। कई प्रोसेसर 2- और 4-बाइट मात्राओं (उदाहरण के लिए इनट्स और लम्बी चींटियों) तक नहीं पहुंच सकते हैं, यदि वे हर तरह से क्रैम होते हैं।

मान लीजिए कि आपके पास यह संरचना है:

struct {
    char a[3];
    short int b;
    long int c;
    char d[3];
};

अब, आप सोच सकते हैं कि इस संरचना को इस तरह स्मृति में पैक करना संभव होना चाहिए:

+-------+-------+-------+-------+
|           a           |   b   |
+-------+-------+-------+-------+
|   b   |           c           |
+-------+-------+-------+-------+
|   c   |           d           |
+-------+-------+-------+-------+

लेकिन प्रोसेसर पर यह बहुत आसान है अगर संकलक इसे इस तरह व्यवस्थित करता है:

+-------+-------+-------+
|           a           |
+-------+-------+-------+
|       b       |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           |
+-------+-------+-------+

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

+-------+-------+-------+-------+
|           a           | pad1  |
+-------+-------+-------+-------+
|       b       |     pad2      |
+-------+-------+-------+-------+
|               c               |
+-------+-------+-------+-------+
|           d           | pad3  |
+-------+-------+-------+-------+

यदि आप चाहते हैं कि संरचना जीसीसी के साथ एक निश्चित आकार हो, उदाहरण के लिए __attribute__((packed)) उपयोग करें।

/ Zp विकल्प के साथ cl.exe compier का उपयोग करते समय आप विंडोज़ पर संरेखण को एक बाइट पर सेट कर सकते हैं।

आम तौर पर सीपीयू के लिए प्लेटफॉर्म और कंपाइलर पर निर्भर करता है, जो 4 (या 8) के एक से अधिक डेटा तक पहुंचने के लिए आसान है।

तो यह मूल रूप से संरेखण का मामला है।

आपको इसे बदलने के अच्छे कारण होने चाहिए।


यह भी देखें:

माइक्रोसॉफ्ट विजुअल सी के लिए:

http://msdn.microsoft.com/en-us/library/2e70t5y1%28v=vs.80%29.aspx

और माइक्रोसॉफ्ट के कंपाइलर के साथ जीसीसी दावा संगतता .:

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html

पिछले उत्तरों के अलावा, कृपया ध्यान दें कि पैकेजिंग पर ध्यान दिए बिना, सी ++ में कोई सदस्य-ऑर्डर-गारंटी नहीं है । कंपाइलर्स आभासी तालिका सूचक और आधार संरचनाओं के सदस्यों को संरचना में जोड़ सकते हैं (और निश्चित रूप से करते हैं)। यहां तक ​​कि आभासी तालिका का अस्तित्व मानक द्वारा सुनिश्चित नहीं किया जाता है (वर्चुअल तंत्र कार्यान्वयन निर्दिष्ट नहीं है) और इसलिए कोई यह निष्कर्ष निकाल सकता है कि ऐसी गारंटी केवल असंभव है।

मुझे पूरा यकीन है कि सदस्य क्रम में सी में गारंटी है , लेकिन क्रॉस-प्लेटफ़ॉर्म या क्रॉस-कंपाइलर प्रोग्राम लिखते समय मैं उस पर भरोसा नहीं करता।


विचार यह है कि गति और कैश विचारों के लिए, संचालन को अपने प्राकृतिक आकार में गठित पते से पढ़ा जाना चाहिए। ऐसा करने के लिए, कंपाइलर पैड संरचना सदस्यों को निम्नलिखित सदस्य या निम्नलिखित संरचना गठबंधन किया जाएगा।

struct pixel {
    unsigned char red;   // 0
    unsigned char green; // 1
    unsigned int alpha;  // 4 (gotta skip to an aligned offset)
    unsigned char blue;  // 8 (then skip 9 10 11)
};

// next offset: 12

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

कुछ आर्किटेक्चरों को वास्तव में गलत तरीके से पढ़ने और लिखने, और एआरएम आर्किटेक्चर के प्रारंभिक संस्करणों (जो आज के सभी मोबाइल सीपीयू में विकसित हुआ) पर जाल करना है ... अच्छा, वे वास्तव में उन लोगों के लिए खराब डेटा लौटाते हैं। (उन्होंने कम ऑर्डर बिट्स को नजरअंदाज कर दिया।)

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

टीएल; डीआर: संरेखण महत्वपूर्ण है।


सी 99 एन 1256 मानक मसौदा

http://www.open-std.org/JTC1/SC22/WG14/www/docs/n1256.pdf

6.5.3.4 आकार का ऑपरेटर :

3 जब ऑपरेशन पर लागू होता है जिसमें संरचना या संघ प्रकार होता है, तो परिणाम आंतरिक और पीछे की पैडिंग सहित ऐसी वस्तु में बाइट्स की कुल संख्या होती है।

6.7.2.1 संरचना और संघ विनिर्देशक :

13 ... संरचना वस्तु के भीतर अज्ञात पैडिंग हो सकती है, लेकिन इसकी शुरुआत में नहीं।

तथा:

15 संरचना या संघ के अंत में अज्ञात पैडिंग हो सकती है।

नई सी 99 लचीला सरणी सदस्य सुविधा ( struct S {int is[];}; ) पैडिंग को भी प्रभावित कर सकती है:

16 एक विशेष मामले के रूप में, एक से अधिक नाम वाले सदस्य के साथ संरचना का अंतिम तत्व अधूरा सरणी प्रकार हो सकता है; इसे एक लचीला सरणी सदस्य कहा जाता है। ज्यादातर स्थितियों में, लचीला सरणी सदस्य को अनदेखा किया जाता है। विशेष रूप से, संरचना का आकार ऐसा लगता है जैसे लचीला सरणी सदस्य छोड़ा गया था, सिवाय इसके कि इसमें चूक से अधिक पीछे की पैडिंग हो सकती है।

अनुलग्नक जे पोर्टेबिलिटी मुद्दे दोहराता है:

निम्नलिखित निर्दिष्ट नहीं हैं: ...

  • संरचनाओं या संघों में मूल्यों को संग्रहीत करते समय पैडिंग बाइट्स का मूल्य (6.2.6.1)

सी ++ 11 एन 3337 मानक मसौदा

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf

5.3.3 आकार :

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

9.2 कक्षा के सदस्य :

मानक-लेआउट स्ट्रक्चर ऑब्जेक्ट के लिए एक पॉइंटर, जो कि reinterpret_cast का उपयोग करके उपयुक्त रूप से रूपांतरित होता है, अपने शुरुआती सदस्य को इंगित करता है (या यदि वह सदस्य थोड़ा-फ़ील्ड है, फिर उस यूनिट में जिसमें वह रहता है) और इसके विपरीत। [नोट: इसलिए मानक-लेआउट स्ट्रक्चर ऑब्जेक्ट के भीतर अज्ञात पैडिंग हो सकती है, लेकिन इसकी शुरुआत में उचित संरेखण प्राप्त करने के लिए आवश्यक नहीं है। - अंत नोट]

मुझे नोट को समझने के लिए केवल पर्याप्त सी ++ पता है :-)


सी भाषा संकलक को स्मृति में संरचनात्मक तत्वों के स्थान के बारे में कुछ स्वतंत्रता छोड़ देता है:

  • मेमोरी छेद किसी भी दो घटकों, और अंतिम घटक के बाद दिखाई दे सकता है। यह इस तथ्य के कारण था कि लक्ष्य कंप्यूटर पर कुछ प्रकार की वस्तुओं को संबोधित करने की सीमाओं तक ही सीमित किया जा सकता है
  • "मेमोरी छेद" आकार आकार ऑपरेटर के परिणाम में शामिल किया गया। आकार में केवल लचीली सरणी का आकार शामिल नहीं है, जो सी / सी ++ में उपलब्ध है
  • भाषा के कुछ कार्यान्वयन आपको प्रगति और कंपाइलर विकल्पों के माध्यम से संरचनाओं के स्मृति लेआउट को नियंत्रित करने की अनुमति देते हैं

सी भाषा संरचना में तत्व लेआउट के प्रोग्रामर को कुछ आश्वासन प्रदान करती है:

  • कंपाइलर्स को मेमोरी पतों को बढ़ाने वाले घटकों के अनुक्रम को आवंटित करने की आवश्यकता होती है
  • पहले घटक का पता संरचना के प्रारंभ पते के साथ मेल खाता है
  • अज्ञात बिट फ़ील्ड संरचना में शामिल तत्वों के आवश्यक पता संरेखण में शामिल किया जा सकता है

तत्व संरेखण से संबंधित समस्याएं:

  • अलग-अलग कंप्यूटर अलग-अलग तरीकों से वस्तुओं के किनारों को रेखाबद्ध करते हैं
  • बिट फ़ील्ड की चौड़ाई पर विभिन्न प्रतिबंध
  • कंप्यूटर एक शब्द में बाइट्स को स्टोर करने के तरीके पर भिन्न होता है (इंटेल 80x86 और मोटोरोला 68000)

संरेखण कैसे काम करता है:

  • संरचना द्वारा कब्जा कर लिया गया मात्रा इस तरह की संरचनाओं की सरणी के गठबंधन एकल तत्व के आकार के रूप में गणना की जाती है। संरचना समाप्त होनी चाहिए ताकि अगली निम्नलिखित संरचना का पहला तत्व संरेखण की उल्लंघन आवश्यकताओं को न करे

पीएस अधिक विस्तृत जानकारी यहां उपलब्ध है: "सैमुअल पी। हार्बिसन, गाय एल .टेले सीए संदर्भ, (5.6.2 - 5.6.7)"







c++-faq