2010-05-14 12 views
10

आज मैंने थोड़ा फ़ील्ड के साथ प्रयोग करते समय खतरनाक व्यवहार की खोज की।जीसीसी, -ओ 2, और बिटफील्ड - क्या यह एक बग या सुविधा है?

#include <stdio.h> 

struct Node 
{ 
    int a:16 __attribute__ ((packed)); 
    int b:16 __attribute__ ((packed)); 

    unsigned int c:27 __attribute__ ((packed)); 
    unsigned int d:3 __attribute__ ((packed)); 
    unsigned int e:2 __attribute__ ((packed)); 
}; 

int main (int argc, char *argv[]) 
{ 
    Node n; 
    n.a = 12345; 
    n.b = -23456; 
    n.c = 0x7ffffff; 
    n.d = 0x7; 
    n.e = 0x3; 

    printf("3-bit field cast to int: %d\n",(int)n.d); 

    n.d++; 

    printf("3-bit field cast to int: %d\n",(int)n.d); 
} 

कार्यक्रम जानबूझकर 3-बिट बिट मैदान ऊपर जाने का कारण है: चर्चा और सादगी के लिए, यहाँ एक उदाहरण कार्यक्रम है। यहाँ (सही) उत्पादन का उपयोग करते समय "जी ++ -O0" संकलित है:

3-सा क्षेत्र डाली int करने के लिए: 7

3-सा क्षेत्र डाली int करने के लिए: 0

यहाँ उत्पादन (और -O3) का उपयोग कर "जी ++ -O2" संकलित:

3-सा क्षेत्र डाली int करने के लिए: 7

3-सा क्षेत्र डाली int करने के लिए: 8

बाद उदाहरण के विधानसभा जाँच हो रही है, मैंने पाया इस:

movl $7, %esi 
movl $.LC1, %edi 
xorl %eax, %eax 
call printf 
movl $8, %esi 
movl $.LC1, %edi 
xorl %eax, %eax 
call printf 
xorl %eax, %eax 
addq $8, %rsp 

अनुकूलन बस डाला है "8", 7 + 1 = 8 संभालने जब वास्तव में संख्या overflows और शून्य है।

सौभाग्य से जिस कोड की मुझे परवाह है, वह मुझे बहती नहीं है, लेकिन यह स्थिति मुझे डराता है - क्या यह एक ज्ञात बग, एक विशेषता है, या यह अपेक्षित व्यवहार है? मैं इस बारे में जीसीसी की सही कब उम्मीद कर सकता हूं?

संपादित करें (पुन: पर हस्ताक्षर किए/अहस्ताक्षरित):

यह है क्योंकि यह अहस्ताक्षरित के रूप में घोषित किया है अहस्ताक्षरित के रूप में इलाज किया जा रहा है। यह घोषणा के रूप में पूर्णांक आप (O0 के साथ) आउटपुट प्राप्त:

3-सा क्षेत्र डाली int करने के लिए: -1

3-सा क्षेत्र डाली int करने के लिए: 0

एक भी int करने के लिए

3-सा क्षेत्र डाली: मजेदार बात यह है कि इस मामले में -O2 के साथ होता है 7

3-सा क्षेत्र डाली int करने के लिए: 8

मैं मानता हूं कि विशेषता उपयोग करने के लिए एक फिश चीज है; इस मामले में यह ऑप्टिमाइज़ेशन सेटिंग्स में एक अंतर है जिसके बारे में मुझे चिंतित है।

+1

शेडकेड जीसीसी 4.4.1 - आउटपुट 7/0 के साथ/अनुकूलन के बिना – dimba

+0

मैं मानता हूं कि मैं 4.1.2 का उपयोग कर रहा हूं - सिर के लिए धन्यवाद। – Rooke

+0

यदि आप पूरी संरचना के बाद '__attribute __ ((__ पैक __)) डालते हैं तो क्या होता है? –

उत्तर

8

यदि आप तकनीकी प्राप्त करना चाहते हैं, तो जिस मिनट में आपने __attribute__ (लगातार दो अंडरस्कोर वाले पहचानकर्ता) का उपयोग किया है, तो आपके कोड में अनिश्चित व्यवहार है।

यदि आपको उन लोगों के साथ समान व्यवहार मिलता है, तो यह मुझे एक कंपाइलर बग की तरह दिखता है। तथ्य यह है कि 3-बिट फ़ील्ड को 7 के रूप में माना जा रहा है, इसका मतलब है कि इसे बिना हस्ताक्षरित माना जा रहा है, इसलिए जब आप ओवरफ्लो करते हैं तो इसे किसी अन्य हस्ताक्षरित की तरह करना चाहिए, और आपको मॉड्यूलो अंकगणित देना चाहिए।

बिट-फील्ड को हस्ताक्षरित के रूप में इलाज करने के लिए यह भी वैध होगा। इस मामले में पहला परिणाम -1, -3 या -0 (जो केवल 0 के रूप में प्रिंट हो सकता है), और दूसरा अपरिभाषित (क्योंकि एक हस्ताक्षरित पूर्णांक का ओवरफ़्लो अपरिभाषित व्यवहार देता है)। सिद्धांत रूप में, अन्य मूल्य C89 या वर्तमान C++ मानक के तहत संभव हो सकते हैं क्योंकि वे हस्ताक्षरित पूर्णांक के प्रतिनिधित्व को सीमित नहीं करते हैं। सी 99 या सी ++ 0x में, यह केवल उन तीनों (सी 99 सीमाएं किसी के पूरक के लिए पूर्णांक पर हस्ताक्षर कर सकती हैं, दो पूरक या साइन-आयाम और सी ++ 0x सी 9 0 के बजाय सी 99 पर आधारित है)।

ओह्स: मैंने पर्याप्त ध्यान नहीं दिया - क्योंकि इसे unsigned के रूप में परिभाषित किया गया है, इसे unsigned के रूप में माना जाना चाहिए, जिससे कंप्रेसर बग होने से बाहर निकलने के लिए थोड़ा विग्लू कमरा छोड़ दिया जाता है।

+0

बेहतर उत्तर, +1 – WhirlWind

+0

__attribute __ के को हटाने से -O2 के साथ गलत व्यवहार भी होता है, लेकिन ओ0 (मूल कोड के अनुसार) नहीं। ऐसा लगता है कि मुझे जीसीसी 4.4 का उपयोग करने की ज़रूरत है! – Rooke

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