सी में संरचना मेमोरी लेआउट


85

मेरे पास C # बैकग्राउंड है। मैं बहुत सी से निम्न स्तर की भाषा का नौसिखिया हूँ।

सी # में, structडिफ़ॉल्ट रूप से संकलक द्वारा मेमोरी रखी जाती है। संकलक डेटा फ़ील्ड्स को फिर से ऑर्डर कर सकता है या अतिरिक्त रूप से फ़ील्ड के बीच अतिरिक्त बिट्स को पैड कर सकता है। इसलिए, मुझे सटीक लेआउट के लिए इस व्यवहार को ओवरराइड करने के लिए कुछ विशेष विशेषता निर्दिष्ट करनी थी।

AFAIK, C structडिफ़ॉल्ट रूप से मेमोरी लेआउट को पुनः व्यवस्थित या संरेखित नहीं करता है । हालाँकि, मैंने सुना है कि थोड़ा अपवाद है जिसे खोजना बहुत कठिन है।

C का मेमोरी लेआउट व्यवहार क्या है? क्या फिर से आदेश दिया जाना चाहिए / गठबंधन और नहीं?

जवाबों:


110

सी में, संकलक को प्रत्येक आदिम प्रकार के लिए कुछ संरेखण निर्धारित करने की अनुमति है। आमतौर पर संरेखण प्रकार का आकार होता है। लेकिन यह पूरी तरह से कार्यान्वयन-विशिष्ट है।

पैडिंग बाइट्स पेश किए जाते हैं ताकि हर वस्तु ठीक से संरेखित हो। पुन: व्यवस्थित करने की अनुमति नहीं है।

संभवतः प्रत्येक आधुनिक आधुनिक संकलक उपकरण, #pragma packजो पैडिंग पर नियंत्रण रखने की अनुमति देता है और एबीआई के अनुपालन के लिए इसे प्रोग्रामर पर छोड़ देता है। (यह कड़ाई से गैरमानक है, हालांकि।)

C99 से §6.7.2.1:

12 संरचना या यूनियन ऑब्जेक्ट के प्रत्येक गैर-बिट-फील्ड सदस्य को उसके प्रकार के कार्यान्वयन-परिभाषित तरीके से संरेखित किया जाता है।

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


1
कुछ संकलक (यानी GCC) उसी प्रभाव को लागू करते हैं, #pragma packलेकिन शब्दार्थ पर अधिक बारीक नियंत्रण के साथ।
क्रिस लुत्ज

21
मैं एक डाउनवोट को देखकर हैरान हूं। किसी को भी त्रुटि इंगित कर सकते हैं?
पोटाटोस्वाटर

2
C11 भी है _Alignas
इदमीन

117

यह कार्यान्वयन-विशिष्ट है, लेकिन नियम के अनुसार ( #pragma packया जैसी अनुपस्थिति में ) है:

  • संरचना सदस्यों को उस क्रम में संग्रहीत किया जाता है जिसे वे घोषित किए जाते हैं। (यह C99 मानक द्वारा आवश्यक है, जैसा कि पहले यहां बताया गया है।)
  • यदि आवश्यक हो, सही संरेखण सुनिश्चित करने के लिए, प्रत्येक संरचनात्मक सदस्य से पहले पैडिंग को जोड़ा जाता है।
  • प्रत्येक आदिम प्रकार टी को sizeof(T)बाइट्स के संरेखण की आवश्यकता होती है ।

इसलिए, निम्नलिखित संरचना दी गई है:

struct ST
{
   char ch1;
   short s;
   char ch2;
   long long ll;
   int i;
};
  • ch1 ऑफसेट 0 पर है
  • एक गद्दी बाइट संरेखित करने के लिए डाला जाता है ...
  • s ऑफसेट 2 पर
  • ch2 ऑफसेट 4 पर है, तुरंत s के बाद
  • 3 पैडिंग बाइट्स को संरेखित करने के लिए डाला जाता है ...
  • ll ऑफसेट 8 पर
  • i ठीक 16 के बाद होगा, ठीक बाद में
  • 4 पैडिंग बाइट्स को अंत में जोड़ा जाता है ताकि समग्र संरचना 8 बाइट्स की एक बहु हो। मैंने 64-बिट सिस्टम पर यह जांचा: 32-बिट सिस्टम 4-बाइट संरेखण के लिए संरचनाओं की अनुमति दे सकता है।

तो sizeof(ST)२४ है।

गद्दी से बचने के लिए सदस्यों को पुनर्व्यवस्थित करके इसे 16 बाइट्स तक कम किया जा सकता है:

struct ST
{
   long long ll; // @ 0
   int i;        // @ 8
   short s;      // @ 12
   char ch1;     // @ 14
   char ch2;     // @ 15
} ST;

3
यदि neccessary, padding पहले जोड़ा गया है ... जैसा कि बाद में। charअपने उदाहरण में अंतिम सदस्य जोड़ें ।
Deduplicator

9
एक आदिम प्रकार को sizeof(T)बाइट्स के संरेखण की आवश्यकता नहीं है । उदाहरण के लिए, एक doubleसामान्य 32-बिट आर्किटेक्चर 8 बाइट्स है, लेकिन अक्सर केवल 4-बाइट संरेखण की आवश्यकता होती है । इसके अलावा, संरचना के अंत में पैडिंग केवल सबसे विस्तृत संरचना के सदस्य के संरेखण के लिए पैड है। उदाहरण के लिए, 3 चार चर की एक संरचना में कोई गद्दी नहीं हो सकती है।
मैट

1
@ dan04, क्या यह आकार (T) के अवरोही क्रम में ढांचों को लेआउट करने के लिए एक अच्छा अभ्यास होगा। क्या ऐसा करने के लिए कोई डाउनसाइड होगा?
रोहितमट

11

डेटा संरेखण की बेहतर समझ पाने के लिए आप डेटा संरचना संरेखण विकिपीडिया लेख को पढ़कर शुरू कर सकते हैं ।

वहाँ से विकिपीडिया लेख :

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

से 6.54.8 संरचना-पैकिंग pragmas जीसीसी दस्तावेज की:

Microsoft Windows कंपाइलरों के साथ संगतता के लिए, GCC #pragma निर्देशों के एक सेट का समर्थन करता है जो संरचनाओं के सदस्यों के अधिकतम संरेखण (शून्य-चौड़ाई बिटफ़िल्ड के अलावा), यूनियनों और वर्गों को बाद में परिभाषित करता है। हमेशा नीचे का मान दो की एक छोटी शक्ति होना आवश्यक है और बाइट्स में नए संरेखण को निर्दिष्ट करता है।

  1. #pragma pack(n) बस नया संरेखण सेट करता है।
  2. #pragma pack() संरेखण शुरू होने पर एक के लिए संरेखण सेट करता है (यह भी कमांड लाइन विकल्प -fpack- संरचना [=] कोड जनरल विकल्प देखें)।
  3. #pragma pack(push[,n]) एक आंतरिक स्टैक पर वर्तमान संरेखण सेटिंग को धक्का देता है और फिर वैकल्पिक रूप से नया संरेखण सेट करता है।
  4. #pragma pack(pop)आंतरिक स्टैक के शीर्ष पर सहेजी गई एक के लिए संरेखण सेटिंग को पुनर्स्थापित करता है (और उस स्टैक प्रविष्टि को हटाता है)। ध्यान दें कि #pragma pack([n])यह आंतरिक स्टैक को प्रभावित नहीं करता है; इस प्रकार #pragma pack(push) कई #pragma pack(n) उदाहरणों के बाद और किसी एकल द्वारा अंतिम रूप दिया जाना संभव है #pragma pack(pop)

कुछ लक्ष्य, उदाहरण के लिए i386 और powerpc, ms_struct का समर्थन करते हैं #pragmaजो दस्तावेज के रूप में एक संरचना देता है __attribute__ ((ms_struct))

  1. #pragma ms_struct on घोषित संरचनाओं के लिए लेआउट पर।
  2. #pragma ms_struct off घोषित संरचनाओं के लिए लेआउट बंद कर देता है।
  3. #pragma ms_struct reset डिफ़ॉल्ट लेआउट पर वापस जाता है।

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