2013-06-07 14 views
6

मैं संरचनाओं के साथ काम कर रहा हूं और उनके बारे में कई प्रश्न हैं। जैसा कि मैं समझता हूं संरचना संरचना को क्रमशः स्मृति में रखा जाएगा। ब्लॉक (शब्द) की लंबाई मशीन आर्किटेक्चर (32 बिट - 4 बाइट, 64 बिट - 8 बाइट्स) पर निर्भर करती है।सी: डेटा संरचना संरेखण

चलें कहते हैं कि हम 2 डेटा संरचनाओं है:

struct ST1 { 
    char c1; 
    short s; 
    char c2; 
    double d; 
    int i; 
}; 

स्मृति में यह हो जाएगा:

32 bit - 20 bytes  
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 
------------------------------------------------------------------------------------------ 
c1| PB| s | s | c1| PB| PB| PB| d | d | d | d | d | d | d | d | i | i | i | i | 

64 bit - 24 bytes | 20 | 21 | 22 | 23 | 
previous sequence + --------------------- 
        | PB | PB | PB | PB | 

लेकिन हम यह पुनर्व्यवस्थित कर सकते हैं, मशीन शब्द में इस डेटा फिट बनाने के लिए। इस तरह:

struct ST2 { 
    double d; 
    int i; 
    short s; 
    char c1; 
    char c2; 
}; 

दोनों 32 और 64 बिट यह उसी तरह से प्रतिनिधित्व किया जाएगा के लिए इस मामले में (16 बाइट्स):

    :

    0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 
    ---------------------------------------------------------------------- 
    d | d | d | d | d | d | d | d | i | i | i | i | s | s | ch1| ch2| 
    

    मैं सवालों की एक जोड़ी

  • यह जंगली अनुमान की तरह है लेकिन struct के लिए मुख्य नियम शुरुआत में बड़े आकार वाले चर को परिभाषित करना है?
  • जैसा कि मैं समझता हूं कि यह स्टैंड-अलोन चर के साथ काम नहीं कर रहा है। char str[] = "Hello"; की तरह?
  • पैडिंग बाइट, इसका कोड क्या है? क्या यह कहीं ASCII तालिका में है? क्षमा करें, इसे नहीं मिला।
  • विभिन्न सदस्यों द्वारा स्मृति में प्रतिनिधित्व किए गए सभी सदस्यों के साथ 2 संरचनाएं और उन्हें स्मृति में अनुक्रमिक रूप से नहीं रखा जा सकता है?
  • ऐसी संरचना: struct ST3 { char c1; char c2; char c3;} st3; size = 3 है, मैं समझता हूं कि यदि हम किसी अन्य सदस्य के साथ सदस्य जोड़ देंगे, तो इसे गठबंधन किया जाएगा। लेकिन यह इससे पहले गठबंधन क्यों नहीं है?

उत्तर

-1

सावधान रहें, आपको यकीन नहीं है कि आपके चर संरेखित हैं (लेकिन यह अक्सर होता है)। यदि आप जीसीसी का उपयोग करते हैं तो आप विशेषता का उपयोग करके यह सुनिश्चित कर सकते हैं कि आपके डेटा गठबंधन किए गए हैं।

उदाहरण:

struct foo { 
    char c; 
    int x; 
} __attribute__((packed)); 

मैं समझता हूँ के रूप में इसके साथ स्टैंड-अलोन चर काम नहीं कर रहा। चार str की तरह [] = "हैलो" ;?

यह तालिका आपकी स्मृति में गठबंधन की जाएगी।

+2

प्रतीक्षा करें, क्या? 'पैक' का उपयोग करके पैडिंग से छुटकारा पड़ेगा, संभावित रूप से सदस्यों को * सही * गठबंधन करने के लिए मजबूर नहीं किया जा सकता है, जिनके प्रभाव x86 पर भी प्रभाव डालते हैं (उदाहरण के लिए 'डबल' तक पहुंच केवल तभी परमाणु है जब यह सही ढंग से गठबंधन हो) – Christoph

+1

क्रिस्टोफ कहता है, यह उत्तर पूर्ण गलत जानकारी है। – Casey

0

के रूप में उत्पन्न

यह जंगली अनुमान लेकिन मुख्य नियम struct के लिए शुरुआत में बड़ा आकार के साथ चर निर्धारित करने के लिए है की तरह है (संरचना के अपने बहुत अच्छी तस्वीर अनदेखी) अपने प्रश्नों का उत्तर देना?

हमेशा उन सामानों को रखें जिन्हें सबसे अधिक संरेखण की आवश्यकता होती है। उदाहरण के लिए मैं पहले char[99] नहीं डालूंगा। आम तौर पर यह पॉइंटर्स, 64 बिट देशी प्रकार, 32 बिट देशी प्रकार इत्यादि के रूप में काम करता है, लेकिन यदि आपकी संरचना में अन्य संरचनाएं हैं तो आपको बहुत सावधान रहना होगा।

जैसा कि मैं समझता हूं कि यह स्टैंड-अलोन चर के साथ काम नहीं कर रहा है। char str[] = "Hello";

मुझे वास्तव में यह समझ में नहीं आता है। यदि आप स्टैक पर एक चार सरणी परिभाषित करते हैं, तो इसमें चार संरेखण होता है। यदि आप एक int के बाद एक चार सरणी परिभाषित करते हैं, तो शायद स्टैक पर पैडिंग होगा, आप इसे नहीं ढूंढ पाएंगे।

पैडिंग बाइट, इसका कोड क्या है? क्या यह कहीं ASCII तालिका में है? क्षमा करें, इसे नहीं मिला।

इसमें न तो कोड और न ही डेटा है। यह संकलक सम्मिलित पैडिंग है और इसमें कोई भी मूल्य हो सकता है, जो प्रोग्राम के समान या अलग-अलग रनों में संरचना के विभिन्न उदाहरणों के बीच अलग हो सकता है या नहीं।

विभिन्न सदस्यों द्वारा स्मृति में प्रतिनिधित्व किए गए सभी सदस्यों के साथ 2 संरचनाएं और उन्हें स्मृति में अनुक्रमिक रूप से नहीं रखा जा सकता है?

मुझे यह समझ में नहीं आता है। क्या आप पूछ रहे हैं कि संकलक संरचनाओं के बीच पैडिंग डाल सकता है या नहीं? यदि नहीं, तो कृपया स्पष्टीकरण दें, क्योंकि यह उत्तर बहुत मदद नहीं करेगा;

जब संकलक संरचना बनाता है, तो इसे आपके लिए ऐसी संरचनाओं की एक सरणी बनाने के लिए संभव बनाना है। इस पर विचार करें: संकलक लडखडाना के बाद गद्दी के 3 बाइट्स सम्मिलित नहीं है

struct S { 
    int wibble; 
    char wobble; 
}; 

S stuff[2]; 

हैं, stuff[1].wobble करने तक पहुँचता है ठीक से संरेखित नहीं की जाएगी, जो कुछ हार्डवेयर पर दुर्घटनाओं (और अन्य हार्डवेयर पर नृशंस प्रदर्शन) में परिणाम होगा । असल में, कंपाइलर को यह सुनिश्चित करने के लिए अंत में पैडिंग सुनिश्चित करना होता है कि संरचना के सबसे गठबंधन सदस्य हमेशा ऐसी संरचनाओं की सरणी के लिए सही ढंग से गठबंधन होते हैं।

ऐसी संरचना: struct ST3 { char c1; char c2; char c3;} st3; आकार = 3 है, मैं समझता हूं कि यदि हम किसी अन्य सदस्य के साथ सदस्य जोड़ देंगे, तो इसे गठबंधन किया जाएगा। लेकिन यह इससे पहले गठबंधन क्यों नहीं है?

क्या आपका मतलब है 'संकलक इसे किसी ऐसे स्थान पर क्यों नहीं डालता जहां यह सही ढंग से गठबंधन किया गया हो'? क्योंकि भाषा इसे नहीं देती है। कंपाइलर को आपकी संरचना के सदस्यों को पुन: व्यवस्थित करने की अनुमति नहीं है। यह केवल पैडिंग डालने की अनुमति है।

0

संरचनाओं (और कक्षाओं) के सदस्य का संरेखण मंच पर, सत्य, लेकिन संकलक पर भी निर्भर करता है। सदस्यों को अपने आकार में संरेखित करने का कारण प्रदर्शन कारण के लिए है। अपने आकार के साथ गठबंधन किए गए सभी अभिन्न प्रकार को स्मृति पहुंच को कम करें।

आप आमतौर पर संरेखण को कम करने के लिए संकलक को मजबूर कर सकते हैं, लेकिन विशिष्ट कारणों को छोड़कर एक अच्छा विचार नहीं है (उदाहरण के लिए, विभिन्न प्लेटफ़ॉर्म के बीच डेटा संगतता के लिए, संचार डेटा के रूप में)। दृश्य C++ में उस के लिए #pragma pack मौजूद है, उदाहरण के लिए:

#pragma pack(1) 
struct ST1 { 
    char c1; 
    short s; 
    char c2; 
    double d; 
    int i; 
}; 

assert(sizeof(ST1) == 16); 

लेकिन जैसा कि मैंने पहले भी कहा आम तौर पर एक अच्छा विचार नहीं है।

ध्यान रखें कि कंपाइलर कुछ फ़ील्ड के बाद पैड बाइट जोड़ रहा है। यह भी आश्वासन देता है कि सभी क्षेत्रों के लिए स्मृति में आवंटित संरचना सही गठबंधन है।मेरा मतलब है, अपने ST1 नमूने में, क्योंकि बड़ा क्षेत्र प्रकार पर दो है, संकलक आश्वासन दिया जाएगा d क्षेत्र 8 बाइट्स पर गठबंधन किया जाएगा (#pragma pack या इसी तरह के विकल्पों का उपयोग करता है, तो छोड़कर):

ST1 st1; 

assert(&st1.d % 8 == 0); 

आपके प्रश्नों के बारे में:

  • यदि आप स्थान को सहेजना चाहते हैं, तो हाँ, आकार के अनुसार एक अच्छा चाल आदेश फ़ील्ड है, पहले सबसे बड़ा लिखना। रचनाकृत structs के मामले में, संरचना के आकार के बजाय, आंतरिक संरचना के बड़े क्षेत्र के आकार का उपयोग करें।
  • यह स्टैंडअलोन चर पर काम कर रहा है। लेकिन संकलक स्मृति में चर को ऑर्डर कर सकता है (जैसा कि structs और वर्गों के सदस्य के रूप में विरोध किया जाता है)।

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

short s[27]; 
int32_t i32[34]; 
int64_t i64[45]; 

assert(s % 2 == 0); 
assert(i32 % 4 == 0); 
assert(i64 % 8 == 0); 
  • पैडिंग बाइट्स कर सकते हैं कुछ भी शामिल हैं। आमतौर पर प्रारंभिक डेटा (कम से कम आप इसे प्रारंभ करते हैं)। डिबगिंग कारणों के लिए, कुछ बार कंपाइलर द्वारा विशिष्ट बाइट पैटर्न हो सकता है।
  • विभिन्न सदस्यों द्वारा स्मृति में प्रतिनिधित्व किए गए सभी सदस्यों के साथ संरचनाओं के बारे में: क्षमा करें, मैं समझता हूं कि आप क्या पूछ रहे हैं।
  • मानक सी ++ का कहना है कि संरचना/वर्ग का पता ऐसी संरचना/कक्षा के पहले क्षेत्र के पते का होना चाहिए। फिर, केवल c3 के बाद संभव पैडिंग है, लेकिन c1 से पहले कभी नहीं।

N3337 (सी ++ 11) [9.2 class.menu, p.20] से:

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

3

बुनियादी नियमों को सरल कर रहे हैं:

  • सदस्यों क्रम में होना चाहिए (जब तक कि C++ आप निजी उपयोग करें: सार्वजनिक: ... वर्गों)
  • गद्दी है सदस्यों के बीच और अंतिम

इसके बारे में यह अनुमति है। शेष कार्यान्वयन के लिए छोड़ दिया गया है: प्रकार, पैडिंग राशि द्वारा लिया भंडारण। आम तौर पर आप एबीआई या सीधे कंपाइलर में उचित रूप से प्रलेखित होने की उम्मीद कर सकते हैं, और यहां तक ​​कि हेरफेर के लिए भी उपकरण हैं।

अभ्यास गद्दी में जरूरी है कि कुछ आर्किटेक्चर पर, कहते हैं कि स्पार्क की आवश्यकता है 32-बिट "ints" पता विभाज्य पर गठबंधन 4. द्वारा दूसरों पर यह आवश्यकता नहीं है, लेकिन गलत संरेखित संस्थाओं पर कार्रवाई करने के लिए और अधिक समय लग सकता है, का कहना है कि एक प्रोसेसर एक विषम पते से 16-बिट इकाई को पढ़ने के लिए एक अतिरिक्त चक्र लेता है। (इससे पहले कि मैं भूल जाऊं: प्रकारों का प्रतिनिधित्व स्वयं अलग है!)

यह सामान्य है कि संरेखण आवश्यकता या सर्वोत्तम प्रदर्शन बिल्कुल ठीक है: आप आकार के समान सीमा पर संरेखित करेंगे। एक अच्छा जवाबी उदाहरण 80-बिट चल बिन्दु संख्या (कुछ compilers में डबल या लंबी डबल के रूप में उपलब्ध) में की तरह 8 या 16 बाइट संरेखण के बजाय 10

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

नीचे की रेखा है, यदि आप लेआउट के साथ बेवकूफ़ बनाना चाहते हैं, तो आप जानते हैं कि वे क्या करते हैं और भविष्य में, उन सभी कंपाइलरों के डॉक्स को पढ़ना शुरू करते हैं, जो यह जानते हैं कि वे क्या करते हैं और इसे कैसे नियंत्रित करें। संभावित रूप से लेआउट में रुचि रखने के आधार पर संभावित प्लेटफ़ॉर्म के डॉक्स को संभवतः पढ़ें।

एक सामान्य प्रेरणा एक स्थिर लेआउट रखना है क्योंकि आप फाइल को कच्ची मेमोरी लिखते हैं और इसे वापस पढ़ने की उम्मीद करते हैं। शायद विभिन्न संकलक का उपयोग कर विभिन्न मंच पर। यह एक आसान प्लेटफॉर्म प्रकार दृश्य में प्रवेश करने तक आसान है।

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

और कुछ कार्यों के सही संयोजन की आवश्यकता होती है, लेकिन सीधे संकलक द्वारा लागू नहीं कर रहे हैं, तो आप (जैसे कुछ SSE से संबंधित सामान के लिए) विशेष संरेखण pragmas लागू करने की आवश्यकता हो सकती है।

नीचे की रेखा दोहराई गई: अनुमान लगाने से रोकें, अपने लक्ष्य तय करें और उचित डॉक्स पढ़ें। (Btw मुझे के लिए वास्तुकला मैनुअल पढ़ने स्पार्क, IA32 और दूसरों के लिए जबरदस्त मज़ा और कई मामलों में लाभ था।)

0
इंटेल वास्तुकला पर एक जीसीसी इसके उपयोग करने के लिए अधिक निर्देशों और चक्र लेता है के लिए

(पठन/लेखन) अजीब क्रमांकित स्मृति पता। इसलिए पैडिंग को भी अंक में जोड़ा गया है स्मृति संख्या

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