2008-11-04 16 views
23

मैं सख्त एलियासिंग नियमों को समझने की कोशिश कर रहा हूं क्योंकि वे चार सूचक पर लागू होते हैं।सख्त पॉइंटर एलियासिंग के लिए char * सुरक्षित कब होता है?

Here इस कहा गया है:

यह हमेशा माना जाता है कि एक चार * किसी भी वस्तु का एक अन्य नाम का उल्लेख कर सकते।

ठीक सॉकेट कोड के संदर्भ में ऐसा है, तो मैं यह कर सकता:

struct SocketMsg 
{ 
    int a; 
    int b; 
}; 

int main(int argc, char** argv) 
{ 
    // Some code... 
    SocketMsg msgToSend; 
    msgToSend.a = 0; 
    msgToSend.b = 1; 
    send(socket, (char*)(&msgToSend), sizeof(msgToSend); 
}; 

लेकिन तब वहाँ इस बयान

बातचीत सच नहीं है है। चार * के अलावा किसी भी प्रकार के पॉइंटर को एक char * कास्टिंग करना और इसे संदर्भित करना आमतौर पर सख्त एलियासिंग नियम का उल्लंघन होता है।

इसका मतलब यह है कि जब मैं एक चार सरणी recv, मैं एक struct करने के लिए डाली पुनर्व्याख्या नहीं कर सकते जब मैं संदेश की संरचना पता:

struct SocketMsgToRecv 
{ 
    int a; 
    int b; 
}; 

int main() 
{ 
    SocketMsgToRecv* pointerToMsg; 
    char msgBuff[100]; 
    ... 
    recv(socket, msgBuff, 100); 
    // Ommiting make sure we have a complete message from the stream 
    // but lets assume msgBuff[0] has a complete msg, and lets interpret the msg 

    // SAFE!?!?!? 
    pointerToMsg = &msgBuff[0]; 

    printf("Got Msg: a: %i, b: %i", pointerToMsg->a, pointerToMsg->b); 
} 

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

+0

क्या कोड के दूसरे भाग में आपको स्पष्ट रूप से कैसर की आवश्यकता नहीं है? क्या आपने सभी चेतावनियां सक्षम की हैं? –

उत्तर

6

सही, दूसरा उदाहरण सख्त एलियासिंग नियमों का उल्लंघन कर रहा है, इसलिए यदि आप -fstrict-aliasing ध्वज के साथ संकलित करते हैं, तो आपको एक मौका ऑब्जेक्ट कोड मिल सकता है। पूरी तरह से सही समाधान यहाँ एक संघ का उपयोग करने के होगा:

union 
{ 
    SocketMsgToRecv msg; 
    char msgBuff[100]; 
}; 

recv(socket, msgBuff, 100); 

printf("Got Msg: a: %i, b: %i", msg.a, msg.b); 
+1

क्या यह मानक या सिर्फ संकलक के अनुपालन में है जो आपको एक सदस्य को लिखने और दूसरे से पढ़ने के लिए छोड़ देता है? –

+9

संघ पूरी तरह से अनावश्यक है। बस संरचना के लिए एक सूचक ('char *' पर कास्ट) 'recv' को पास करें। –

+0

ध्यान दें कि '-O2' पर डिफ़ॉल्ट रूप से '-फस्ट्रिट-एलाइजिंग' चालू है और जीसीसी –

7

पुन @Adam Rosenfield: संघ इतने लंबे समय के चार * के आपूर्तिकर्ता के रूप में बाहर शुरू कर दिया कुछ इसी तरह कर रही संरेखण प्राप्त करेंगे।

यह वापस खड़े होने और यह पता लगाने के लिए उपयोगी हो सकता है कि यह सब क्या है।

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

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

char * के बारे में क्या?

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

अब आप यह देखने में सक्षम होना चाहिए कि अगर आप किसी प्रकार के संरचना डेटा को एक char [] सरणी में स्थानांतरित करते हैं, जिसे उचित रूप से संरेखित नहीं किया गया था, तो उस संकेतक को वापस डालने का प्रयास करने के लिए जिसे संरेखण की आवश्यकता होती है गंभीर समस्या।

यदि आप एक char [] सरणी और एक संरचना का संघ बनाते हैं, तो सबसे अधिक मांग वाले संरेखण (यानी, संरचना का) को संकलक द्वारा सम्मानित किया जाएगा। यह काम करेगा अगर आपूर्तिकर्ता और उपभोक्ता प्रभावी रूप से मिलियन यूनियनों का उपयोग कर रहे हैं ताकि संरचना * का कास्टिंग * और पीछे काम ठीक हो।

उस स्थिति में, मुझे उम्मीद है कि डेटा को उसी संघ में बनाया गया था इससे पहले कि पॉइंटर को चार पर डाला गया था * या इसे आकार (चार) बाइट्स की सरणी के रूप में किसी अन्य तरीके से स्थानांतरित किया गया था। यह सुनिश्चित करना भी महत्वपूर्ण है कि किसी भी कंपाइलर विकल्प आपके और अपने कोड पर निर्भर पुस्तकालयों के बीच संगत हों।

+0

में उच्चतर '3' चार 'char',' हस्ताक्षरित char', 'unsigned char' aliasing के लिए ठीक है? और किसी भी सीवी-योग्यता संयोजन के साथ ही? –

+2

एलियासिंग नियमों के संरेखण के साथ कुछ लेना देना नहीं है। सीआई 8 तर्क के अनुसार, वैश्विक घोषणाओं जैसे 'int i; फ्लोट * एफपी; ', उद्देश्य संकलक को '* fp' तक पहुंच में एक रजिस्टर में' i' रखने की अनुमति देना है। विचार यह था कि एक कंपाइलर को निराशाजनक रूप से यह मानना ​​नहीं चाहिए कि '* fp' को लिखने से' i' * में परिवर्तन हो सकता है, जब इसकी अपेक्षा करने का कोई कारण नहीं था * कि * * fp' उस चीज़ पर इंगित करेगा जो ' float' *। मुझे नहीं लगता कि नियम कभी भी कंपाइलर्स को ऐसे मामलों को अनदेखा करने का इरादा रखता था जहां एलियासिंग स्पष्ट है (किसी ऑब्जेक्ट का पता लेना एक कंपाइलर को एक मजबूत सुराग देना चाहिए ... – supercat

+0

... कि वस्तु में प्रश्न का उपयोग किया जा रहा है सूचक के माध्यम से, और 'फ्लोट *' के लिए 'int * 'कास्टिंग करने के लिए कंपाइलर को एक मजबूत सुराग देना चाहिए कि' int 'को' float *' पर लिखकर संशोधित किया जा सकता है, लेकिन जीसीसी को अब कोई दायित्व नहीं है ऐसी चीजों को नोटिस करें। – supercat

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