2015-07-07 7 views
28

इस साधारण प्रोग्रामयह स्ट्रक्चर पैडिंग चाल क्यों काम करता है?

#include <iostream> 

struct A 
{ 
    int x1234; 
    short x56; 
    char x7; 
}; 

struct B : A 
{ 
    char x8; 
}; 

int main() 
{ 
    std::cout << sizeof(A) << ' ' << sizeof(B) << '\n'; 
    return 0; 
} 

यह प्रिंट 8 12 पर विचार करें। भले ही B संरेखण आवश्यकताओं को तोड़ने के बिना 8 बाइट्स में पैक किया जा सकता है, इसके बजाय यह एक लालची 12 बाइट लेता है।

sizeof(B) == 8 होना अच्छा लगेगा, लेकिन Is the size of a struct required to be an exact multiple of the alignment of that struct? का उत्तर बताता है कि कोई रास्ता नहीं है।

मैं जब निम्न

struct MakePackable 
{ 
}; 

struct A : MakePackable 
{ 
    int x1234; 
    short x56; 
    char x7; 
}; 

struct B : A 
{ 
    char x8; 
}; 

मुद्रित 8 8 इसलिए आश्चर्य हुआ।

यहां क्या हो रहा है? मुझे संदेह है कि मानक-लेआउट-प्रकारों के साथ कुछ करने के लिए कुछ है। यदि हां, तो उपर्युक्त व्यवहार के कारण इसके लिए तर्क क्या है, जब उस सुविधा का एकमात्र उद्देश्य सी के साथ बाइनरी-संगतता सुनिश्चित करना है?


संपादित करें: जैसा कि अन्य लोगों ने बताया है इस ABI या संकलक विशिष्ट है, इसलिए मैं जोड़ने के लिए है कि इस व्यवहार निम्नलिखित compilers के साथ x86_64-अज्ञात-linux-gnu पर मनाया गया चाहिए:

  • बजना 3.6
  • जीसीसी 5,1

मैं भी कुछ बजना के struct डम्पर से अजीब देखा है। अगर हम डेटा आकार के लिए बिना पूंछ गद्दी ("dsize"),

  A B 
first  8 9 
second 7 8 

तो पहले उदाहरण में पूछना हम dsize(A) == 8 मिलता है। यह 7 क्यों नहीं है?

+0

शायद कंपाइलर कार्यान्वयन के विवरण के अलावा कोई तर्क नहीं है ... – deviantfan

+2

आपको एक विशिष्ट एबीआई के बारे में पूछना होगा, क्योंकि यह व्यवहार सी ++ के दायरे में लगभग शून्य मौका है। एफडब्ल्यूआईडब्ल्यू, मुझे यह समझाने के लिए इटेनियम (एक त्वरित नज़र में) कुछ भी नहीं मिला है, हालांकि मुझे जीसीसी 5.1 के साथ '8 8' मिलता है, इसलिए ...:/ –

+0

क्या टैग [टैग: भाषा-वकील] उपयुक्त है इस सवाल के लिए? –

उत्तर

2

मैं सी ++ का एक वास्तविक भाषा वकील नहीं हूँ, लेकिन मैं क्या पाया है अब तक है:

this question में जवाब संदर्भित, एक struct केवल एक मानक लेआउट पॉड बनी हुई है, जबकि वहाँ के साथ ही 1 वर्ग है अपने और उसके माता-पिता वर्गों के बीच गैर स्थैतिक सदस्य। तो उस विचार के तहत A दोनों मामलों में एक गारंटीकृत लेआउट है, लेकिन Bमें मामले में नहीं है।

इसका समर्थन करना यह तथ्य है कि std::is_podA के लिए सच है और दोनों में B के लिए गलत है।

तो अगर मैं इस सही ढंग से अपने आप को समझने रहा हूँ, संकलक कुछ कमरे क्या उस में B के लेआउट के साथ चाहता है ऐसा करने के लिए अनुमति दी है दोनों घटनायें। और स्पष्ट रूप से दूसरे मामले में ऐसा लगता है कि अन्यथा A के पैडिंग बाइट क्या होगा।

+0

एक मानक लेआउट क्लास: _ "या तो सबसे व्युत्पन्न वर्ग में कोई गैर-स्थैतिक डेटा सदस्य नहीं है और गैर-स्थैतिक डेटा सदस्यों वाले अधिकांश बेस क्लास में, या गैर स्थैतिक डेटा सदस्यों के साथ कोई आधार वर्ग नहीं है" _ '[सी ++ 14: 9/7] ' –

+0

@ लाइटनेसरेसेसिन ऑर्बिट शब्द [इस प्रस्ताव] के साथ बदल गया है (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1813), और अब मुझे समझ में नहीं आता है। – Barry

2

यह एक डेटा पॉइंट है हालांकि पूरा जवाब नहीं है।यदि struct A : X बजाय प्रयोग किया जाता है, तो

movq (%rdx), %rax 
movq %rax, (%rcx) 

हालांकि:

कहो हम (एक पूर्ण अनुवाद इकाई, नहीं एक टुकड़ा के रूप में):

struct X {}; 

struct A 
{ 
    int x1234; 
    short x56; 
    char x7; 
} 

void func(A &dst, A const &src) 
{ 
    dst = src; 
} 
जी के साथ

++, इस समारोह के लिए संकलित किया गया है यह फ़ंक्शन है:

movl (%rdx), %eax 
movl %eax, (%rcx) 
movzwl 4(%rdx), %eax 
movw %ax, 4(%rcx) 
movzbl 6(%rdx), %eax 
movb %al, 6(%rcx) 

ये दो मामले वास्तव में आकार बी के अनुरूप हैं। ओपी के उदाहरण में क्रमशः 8 12 और 8 8 ईिंग करें।

इस का कारण यह काफी स्पष्ट है: A कुछ वर्ग B के लिए एक आधार के रूप में इस्तेमाल किया जा सकता है, और फिर कॉल func(b, a);b के अन्य सदस्यों को बताया कि ओपी के दशक में गद्दी क्षेत्र (b.x8 में रहते हो सकता है परेशान करने के लिए सावधान नहीं होना चाहिए उदाहरण);

मैं सी ++ मानक में A : X के किसी विशेष संपत्ति जो होगा जी ++ तय करते हैं कि गद्दी struct A : X में फिर से प्रयोग करने योग्य है, लेकिन नहीं struct A में नहीं देख सकता। A और A : X दोनों trivially कॉपी करने योग्य, मानक लेआउट और पीओडी हैं।

मुझे लगता है कि यह सामान्य उपयोग के आधार पर केवल एक अनुकूलन निर्णय होना चाहिए। पुन: उपयोग के बिना संस्करण कॉपी करने के लिए तेज़ होगा। शायद एक जी ++ एबीआई डिजाइनर टिप्पणी कर सकता है?

दिलचस्प बात यह है कि यह उदाहरण दिखाता है कि तुच्छ रूप से प्रतिलिपि बनाने योग्य यह नहीं दर्शाता है कि memcpy(&b, &a, sizeof b)b = a के बराबर है!

+1

मुझे लगता है कि इसे सी संगतता के साथ करना होगा। जबकि एक सी ++ कार्यक्रम को पता होना चाहिए कि किसी भी गैर-अंतिम प्रकार से लिया जा सकता है, और इसलिए डेटा सदस्यों को पैडिंग के भीतर रखा गया है, कोई सी प्रोग्राम इस धारणा की आवश्यकता नहीं है। जब आप किसी प्रकार से 'ए' प्राप्त करते हैं, तो आप सी – dyp

+0

@dyp में सटीक उसी 'स्ट्रक्चर' का उपयोग नहीं कर सकते हैं जो समझ में आता है –

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