2012-07-01 16 views
9

C11, निम्नलिखित struct में काम करते हुए की जीसीसी कार्यान्वयन में बग:बिट क्षेत्रों

struct S { 
    unsigned a : 4; 
    _Bool b : 1; 
}; 

एक unsigned (4 बाइट्स) जिनमें से 4 बिट्स उपयोग किया जाता है के रूप में जीसीसी से बाहर रखी हो जाता है, एक _Bool द्वारा पीछा किया (4 बाइट्स) जिनमें से 1 बिट का उपयोग 8 बाइट्स के कुल आकार के लिए किया जाता है।

ध्यान दें कि सी 99 और सी 11 विशेष रूप से _Bool को बिट-फील्ड सदस्य के रूप में अनुमति देते हैं। सी 11 मानक (और शायद बहुत C99) भी §6.7.2.1 'संरचना और संघ विनिर्देशक' ¶11 के तहत कहा गया है कि:

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

तो मुझे विश्वास है कि सदस्य b ऊपर भंडारण इकाई सदस्य a के लिए आवंटित, कुल आकार 4 बाइट्स की एक struct में जिसके परिणामस्वरूप में पैक किया जाना चाहिए था।

जीसीसी सही ढंग से कार्य और जब दो सदस्यों के लिए एक ही प्रकार का उपयोग कर पैकिंग होती है, या जब एक unsigned और अन्य signed, है, लेकिन प्रकार unsigned और _Bool जीसीसी यह उन्हें संभाल करने के लिए से भी अलग समझा जा करने लगते हैं सही ढंग से।

क्या कोई मानक की मेरी व्याख्या की पुष्टि कर सकता है, और यह वास्तव में एक जीसीसी बग है?

मुझे काम के आसपास भी कुछ दिलचस्पी है (कुछ कंपाइलर स्विच, प्राग्मा, __attribute__ ...)।

मैं जीसीसी 4.7.0 का उपयोग कर रहा साथ -std=c11 (हालांकि अन्य सेटिंग्स समान व्यवहार प्रदर्शित करते हैं।)

+0

ध्यान दें कि जीसीसी एक्सटेंशन '__attribute__ ((पैक)) 'सदस्यों को यहां लागू किया जा सकता है , लेकिन इस समस्या के लिए ऑर्थोगोनल है (इसके परिणामस्वरूप आकार 4 + 1 = 5 की संरचना होती है, यानी एक ही समस्या के साथ।) – ndkrempel

+0

संबंधित: http://stackoverflow.com/questions/308364/c-bitfield-packing-with -बूल (लेकिन सी ++ को संदर्भित करता है, जो कि बिट-फ़ील्ड पर अपने शब्दों में सटीक नहीं है।) – ndkrempel

+0

ऊपर दिए गए प्रश्न के उत्तर के अनुसार, यह व्यवहार जीसीसी 4.2.4 में नहीं हुआ था, इसलिए हो सकता है तब से एक प्रतिगमन। – ndkrempel

उत्तर

10

वर्णित व्यवहार C99 और सी 11 मानकों के अनुरूप नहीं है, लेकिन MSVC संकलक के साथ दोहरी संगतता के लिए प्रदान की जाती है (जो असामान्य struct पैकिंग व्यवहार है।)

सौभाग्य से, यह या तो __attribute__((gcc_struct)) साथ कोड struct, या कमांड लाइन स्विच -mno-ms-bitfields (documentation देखें) के साथ करने के लिए लागू में निष्क्रिय किया जा सकता।

+0

क्या यह कहीं भी प्रलेखित है? मुझे 'mno-ms-bitfields' –

+0

https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#x86- विकल्प – ndkrempel

+0

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

0

का उपयोग करते हुए दोनों जीसीसी 4.7.1 (घर-निर्मित) और मैक ओएस एक्स 10.7.4 पर जीसीसी 4.2.1 (LLVM/बजना †) के 64-बिट संकलन के साथ, इस कोड पैदावार -std=c99 मोड में 4:

#include <stdio.h> 

int main(void) 
{ 
    struct S 
    { 
     unsigned a : 4; 
     _Bool b : 1; 
    }; 
    printf("%zu\n", sizeof(struct S)); 
    return 0; 
} 

यह आधा आकार है जिसे आप विंडोज़ पर रिपोर्ट कर रहे हैं। यह मेरे लिए आश्चर्यजनक रूप से बड़ा लगता है (मुझे उम्मीद है कि यह 1 बाइट का आकार होगा), लेकिन मंच के नियम वे हैं जो वे हैं। असल में, कंपाइलर आपके इच्छित नियमों का पालन करने के लिए बाध्य नहीं है; यह उस प्लेटफ़ॉर्म के नियमों का पालन कर सकता है, जिस पर यह चल रहा है, और जहां इसका मौका है, यह उस प्लेटफॉर्म के नियमों को भी परिभाषित कर सकता है जो इसे चलाया जा रहा है।

यह निम्न कार्यक्रम हल्का संदिग्ध व्यवहार है (क्योंकि यह तक पहुँचता है u.iu.s के बाद पिछले करने के लिए लिखा गया था), लेकिन पता चलता है कि क्षेत्र a 4 कम से कम महत्वपूर्ण बिट में संग्रहित है और क्षेत्र b अगले बिट में संग्रहीत है:

#include <stdio.h> 

int main(void) 
{ 
    union 
    { 
     struct S 
     { 
      unsigned a : 4; 
      _Bool b : 1; 
     } s; 
     int i; 
    } u; 
    u.i = 0; 
    u.s.a = 5; 
    u.s.b = 1; 
    printf("%zu\n", sizeof(struct S)); 
    printf("%zu\n", sizeof(u)); 
    printf("0x%08X\n", u.i); 
    u.s.a = 0xC; 
    u.s.b = 1; 
    printf("0x%08X\n", u.i); 
    return 0; 
} 

आउटपुट:

4 
4 
0x00000015 
0x0000001C 

i686-सेब के darwin11-LLV † एम-जीसीसी-4.2 (जीसीसी) 4.2.1 (ऐप्पल इंक। के आधार पर 5658) (एलएलवीएम बिल्ड 2336.9.00)

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