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


698

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


14
यह देखें सी। मेमोरी एलिगेंस पर अक्सर पूछे जाने वाले प्रश्न। c-faq.com/struct/align.esr.html
रिचर्ड चेम्बर्स

48
किस्सा: एक वास्तविक कंप्यूटर वायरस था जिसने होस्ट प्रोग्राम में अपना कोड स्ट्रक्चर पैडिंग्स के भीतर रखा था।
एलाज़ार

4
@Elazar यह प्रभावशाली है! मैंने कभी भी इस तरह के छोटे क्षेत्रों को किसी भी चीज़ के लिए उपयोग करना संभव नहीं सोचा होगा। क्या आप कोई और विवरण प्रदान करने में सक्षम हैं?
18

1
@Wilson - मुझे यकीन है कि इसमें बहुत सारे jmp शामिल थे।
हुडैटिकस

जवाबों:


649

ऐसा इसलिए है क्योंकि संरेखण बाधाओं को पूरा करने के लिए पैडिंग को जोड़ा गया है। डेटा संरचना संरेखण प्रदर्शन और कार्यक्रमों की शुद्धता दोनों को प्रभावित करता है:

  • मिस-एलाइनिंग एक्सेस एक कठिन त्रुटि (अक्सर SIGBUS) हो सकती है ।
  • मिस-अलाइड एक्सेस एक सॉफ्ट एरर हो सकता है।
    • या तो हार्डवेयर में सुधार, एक मामूली प्रदर्शन-गिरावट के लिए।
    • या एक गंभीर प्रदर्शन-गिरावट के लिए सॉफ्टवेयर में अनुकरण द्वारा सही किया गया।
    • इसके अलावा, परमाणु और अन्य संगामिति-गारंटियां टूट सकती हैं, जिससे सूक्ष्म त्रुटियां हो सकती हैं।

यहाँ x86 प्रोसेसर (सभी 32 और 64 बिट मोड का उपयोग किया गया) के लिए विशिष्ट सेटिंग्स का उपयोग कर एक उदाहरण दिया गया है:

struct X
{
    short s; /* 2 bytes */
             /* 2 padding bytes */
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 3 padding bytes */
};

struct Y
{
    int   i; /* 4 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
    short s; /* 2 bytes */
};

struct Z
{
    int   i; /* 4 bytes */
    short s; /* 2 bytes */
    char  c; /* 1 byte */
             /* 1 padding byte */
};

const int sizeX = sizeof(struct X); /* = 12 */
const int sizeY = sizeof(struct Y); /* = 8 */
const int sizeZ = sizeof(struct Z); /* = 8 */

एक संरेखण द्वारा सदस्यों को छाँटकर संरचनाओं के आकार को कम कर सकते हैं (आकार प्रकारों के लिए आधारभूत प्रकारों में छंटनी) (जैसे Zऊपर उदाहरण में संरचना )।

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


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

35
X86 चिप्स वास्तव में अद्वितीय हैं, क्योंकि वे बिना किसी पहुँच के अनुमति देते हैं, भले ही दंडित किया गया हो; AFAIK अधिकांश चिप्स अपवादों को फेंक देंगे, न कि केवल कुछ। PowerPC एक और आम उदाहरण है।
डार्क शिकारी

6
बिना असाइन किए गए एक्सेस के लिए व्यावहारिक रूप से सक्षम करना आमतौर पर आपके कोड को आकार में गुब्बारे का कारण बनता है, प्रोसेसर पर जो मिसलिग्न्मेंट दोष फेंकते हैं, कोड के रूप में हर मिसलिग्न्मेंट को ठीक करने के लिए उत्पन्न करना पड़ता है। एआरएम भी misalignment दोष फेंकता है।
माइक डिम्मिक

5
@ डार्क - पूरी तरह से सहमत हैं। लेकिन अधिकांश डेस्कटॉप प्रोसेसर x86 / x64 हैं, इसलिए अधिकांश चिप्स डेटा संरेखण दोष जारी नहीं करते हैं;)
एरोन

27
Unalign डेटा एक्सेस आमतौर पर CISC आर्किटेक्चर में पाया जाने वाला एक फीचर है, और अधिकांश RISC आर्किटेक्चर इसमें शामिल नहीं हैं (ARM, MIPS, PowerPC, Cell)। वास्तव में, अधिकांश चिप्स डेस्कटॉप प्रोसेसर नहीं होते हैं, चिप्स की संख्या द्वारा एम्बेडेड नियम के लिए और इनमें से अधिकांश आरआईएससी आर्किटेक्चर हैं।
लारा डगान

192

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

यह संरेखण के लिए है। कई प्रोसेसर 2- और 4-बाइट मात्रा (जैसे ints और लंबी ints) का उपयोग नहीं कर सकते हैं, अगर वे हर तरह से क्रैम्ड होते हैं।

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

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  |
+-------+-------+-------+-------+

1
अब मेमोरी स्लॉट्स पैड 1, पैड 2 और पैड 3 का क्या उपयोग है।
लक्ष्मी श्रीकांत चितला


@EmmEff यह गलत हो सकता है लेकिन मुझे यह पूरी तरह से नहीं आता है: एरे में पॉइंटर के लिए मेमोरी स्लॉट क्यों नहीं है?
बैल्ज़ोस्क

1
@ BalázsBörcsök ये निरंतर आकार के सरणियाँ हैं, और इसलिए उनके तत्व निश्चित रूप से निर्धारित ऑफसेट पर सीधे संरचना में संग्रहीत किए जाते हैं। संकलक को संकलन समय पर यह सब पता है इसलिए सूचक निहित है। उदाहरण के लिए, यदि आपके पास इस प्रकार का एक संरचित चर है, sतो &s.a == &sऔर &s.d == &s + 12(उत्तर में दिखाए गए संरेखण को देखते हुए)। पॉइंटर को केवल तभी संग्रहीत किया जाता है यदि सरणियों का एक चर आकार होता है (जैसे, इसके बजाय aघोषित किया गया था ), लेकिन फिर तत्वों को किसी और के पास संग्रहीत किया जाना है। char a[]char a[3]
kbolino

27

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

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

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

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

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


5
"अच्छे कारण" उदाहरण: बाइनरी कम्पैटिबिलिटी (पैडिंग) को 32-बिट और 64-बिट सिस्टम के बीच प्रूफ-ऑफ-कांसेप्ट डेमो कोड में एक जटिल संरचना के लिए संगत रखना जो कल प्रदर्शित हो रहा है। कभी-कभी आवश्यकता को औचित्य पर वरीयता लेनी पड़ती है।
श्री।

2
ऑपरेटिंग सिस्टम का उल्लेख करने के अलावा सब कुछ ठीक है। यह सीपीयू की गति के लिए एक मुद्दा है, ओएस बिल्कुल शामिल नहीं है।
ब्लिसॉर्बलेड

3
एक और अच्छा कारण यह है कि अगर आप नेटवर्क प्रोटोकॉल को पार्स करते समय एक डेटास्ट्रीम को एक संरचना में भर रहे हैं।
ceo

1
@dolmen मैंने अभी बताया कि "ऑपरेटिंग सिस्टम के लिए डेटा एक्सेस करना आसान है" गलत है, क्योंकि ओएस डेटा एक्सेस नहीं करता है।
ब्लेज़ोरब्लेड

1
@ डोलमेन वास्तव में, किसी को एबीआई (एप्लिकेशन बाइनरी इंटरफ़ेस) के बारे में बात करनी चाहिए। डिफ़ॉल्ट संरेखण (इसका उपयोग अगर आप इसे स्रोत में नहीं बदलते हैं) ABI पर निर्भर करता है, और कई OS कई ABI का समर्थन करते हैं (जैसे, 32- और 64-बिट, या अलग-अलग OS से बायनेरी के लिए, या संकलन के विभिन्न तरीकों के लिए) एक ही ओएस के लिए एक ही बायनेरिज़)। OTOH, क्या संरेखण प्रदर्शन-वार सुविधाजनक है सीपीयू पर निर्भर करता है - मेमोरी उसी तरह एक्सेस की जाती है कि क्या आप 32 या 64 बिट मोड का उपयोग करते हैं (मैं वास्तविक मोड पर टिप्पणी नहीं कर सकता, लेकिन आजकल प्रदर्शन के लिए शायद ही प्रासंगिक लगता है)। IIRC पेंटियम ने 8-बाइट संरेखण को प्राथमिकता देना शुरू कर दिया।
ब्लेज़ोरब्लेड

15

यह बाइट संरेखण और पैडिंग के कारण हो सकता है ताकि संरचना आपके प्लेटफॉर्म पर बाइट्स (या शब्द) की एक समान संख्या के लिए निकले। लिनक्स पर C में उदाहरण के लिए, निम्नलिखित 3 संरचनाएं:

#include "stdio.h"


struct oneInt {
  int x;
};

struct twoInts {
  int x;
  int y;
};

struct someBits {
  int x:2;
  int y:6;
};


int main (int argc, char** argv) {
  printf("oneInt=%zu\n",sizeof(struct oneInt));
  printf("twoInts=%zu\n",sizeof(struct twoInts));
  printf("someBits=%zu\n",sizeof(struct someBits));
  return 0;
}

ऐसे सदस्य हैं जिनके आकार (बाइट्स में) क्रमशः 4 बाइट्स (32 बिट्स), 8 बाइट्स (2x 32 बिट्स) और 1 बाइट (2 + 6 बिट्स) हैं। उपरोक्त कार्यक्रम (लिनक्स पर gcc का उपयोग करके) आकार को 4, 8 और 4 के रूप में प्रिंट करता है - जहां अंतिम संरचना को गद्देदार किया जाता है ताकि यह एक एकल शब्द हो (मेरे 32 बिट प्लेटफॉर्म पर 4 x 8 बिट बाइट्स)।

oneInt=4
twoInts=8
someBits=4

4
"सीसीसी का उपयोग करके लिनक्स पर सी" आपके प्लेटफॉर्म का वर्णन करने के लिए पर्याप्त नहीं है। संरेखण ज्यादातर सीपीयू वास्तुकला पर निर्भर करता है।
dolmen

- @ काइल बर्टन क्षमा करें, मुझे समझ नहीं आया कि "someBits" संरचना का आकार 4 के बराबर क्यों है, मुझे उम्मीद है कि 8 बाइट्स हैं, 2 पूर्णांक घोषित किए गए हैं (2 * sizeof (int)) = 8 बाइट्स। धन्यवाद
youpilat13

1
हाय @ youpilat13, :2और :6वास्तव में 2 और 6 बिट्स निर्दिष्ट कर रहे हैं, इस मामले में पूर्ण 32 बिट पूर्णांक नहीं। someBits.x, केवल 2 बिट्स होने से केवल 4 संभावित मान संग्रहीत किए जा सकते हैं: 00, 01, 10, और 11 (1, 2, 3 और 4)। इसका कोई मतलब भी है क्या? यहाँ फ़ीचर के बारे में एक लेख दिया गया है: geeksforgeeks.org/bit-fields-c
काइल बर्टन

11

यह सभी देखें:

Microsoft Visual C के लिए:

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

और Microsoft के संकलक के साथ GCC का दावा संगतता:

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

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

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


4
"मुझे पूरा यकीन है कि सदस्य-क्रम C में भुना हुआ है"। हां, C99 कहता है: "एक संरचना वस्तु के भीतर, गैर-बिट-फ़ील्ड सदस्य और इकाइयाँ जिनमें बिट-फ़ील्ड रहते हैं, उन पते को बढ़ाते हैं, जिस क्रम में उन्हें घोषित किया जाता है।" अधिक मानक अच्छाई: stackoverflow.com/a/37032302/895245
Ciro Santilli 病::: '


8

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

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

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

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

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

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

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

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

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

I = sizeof(myData);

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


यह संरचना पैडिंग के परिणामों पर चर्चा करता है, लेकिन यह प्रश्न का उत्तर नहीं देता है।
कीथ थॉम्पसन

" ... जिसे पैकिंग कहा जाता है, उसके कारण ... - मुझे लगता है कि आप का अर्थ है" पैडिंग "।" 32-बिट्स (4 बाइट्स) में सबसे आधुनिक प्रोसेसर का पसंदीदा आकार "- यह एक ओवरसिम्प्लीफिकेशन का एक सा है। टाइपिंग।" 8, 16, 32 और 64 बिट्स के आकार का समर्थन किया जाता है; अक्सर प्रत्येक आकार का अपना संरेखण होता है। और मुझे यकीन नहीं है कि आपका उत्तर किसी भी नई जानकारी को जोड़ता है जो पहले से ही स्वीकृत उत्तर में नहीं है।
कीथ थॉम्पसन

1
जब मैंने कहा कि पैकिंग है, तो मेरा मतलब था कि कंपाइलर डेटा को किसी संरचना में कैसे पैक करता है (और ऐसा वह छोटी वस्तुओं को पैड करके कर सकता है, लेकिन इसे पैड करने की आवश्यकता नहीं है, लेकिन यह हमेशा पैक होता है)। आकार के अनुसार - मैं सिस्टम आर्किटेक्चर के बारे में बात कर रहा था, न कि सिस्टम डेटा एक्सेस के लिए समर्थन करेगा (जो कि अंतर्निहित बस आर्किटेक्चर से अलग है)। आपकी अंतिम टिप्पणी के अनुसार, मैंने ट्रेडऑफ़ के एक पहलू (गति बनाम आकार) का एक सरलीकृत और विस्तारित विवरण दिया - एक प्रमुख प्रोग्रामिंग समस्या। मैं समस्या को ठीक करने का एक तरीका भी बताता हूँ - जो स्वीकृत उत्तर में नहीं था।
सिड 1138

इस संदर्भ में "पैकिंग" आमतौर पर सदस्यों को डिफ़ॉल्ट की तुलना में अधिक कसकर आवंटित करने के लिए संदर्भित करता है, जैसा कि #pragma pack। यदि सदस्यों को उनके डिफ़ॉल्ट संरेखण पर आवंटित किया जाता है, तो मैं आमतौर पर कहूंगा कि संरचना पैक नहीं है
कीथ थॉम्पसन

पैकिंग एक अतिभारित शब्द की तरह है। इसका मतलब है कि आप संरचना के तत्वों को स्मृति में कैसे डालते हैं। वस्तुओं को एक बॉक्स में रखने के अर्थ के समान (चलती के लिए पैकिंग)। इसका मतलब यह भी है कि बिना किसी पैडिंग ("कसकर पैक किए गए" के लिए एक छोटे हाथ की तरह) स्मृति में तत्वों को डालना। तब #pragma पैक कमांड में शब्द का कमांड संस्करण है।
साइड 1138

5

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

इसके अलावा एक पुस्तकालय 32-बिट ints के साथ x86 के तहत संकलित किया जा सकता है और आप 64-बिट प्रक्रिया पर इसके घटकों की तुलना कर सकते हैं यदि आप हाथ से ऐसा कर रहे थे तो आपको एक अलग परिणाम मिलेगा।


5

C99 N1256 मानक ड्राफ्ट

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

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

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

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

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

तथा:

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

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

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

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

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

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

C ++ 11 N3337 मानक ड्राफ्ट

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

5.3.3 आकार :

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

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

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

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


4

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


8
काफी नहीं। विशिष्ट कार्यान्वयन में, जो संरचना में जोड़ा जाता है वह एक वाइबेट पॉइंटर है
डॉन वेकफील्ड

3

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

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

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

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

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

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

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

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

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


2

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

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 आर्किटेक्चर हमेशा गलत पते प्राप्त करने में सक्षम रहा है। हालांकि, यह धीमा है और जब मिसलिग्न्मेंट दो अलग-अलग कैश लाइनों को ओवरलैप करता है, तो यह दो कैश लाइनों को दिखाता है जब एक संरेखित एक्सेस केवल एक बेदखल करेगा।

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

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

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

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