2010-07-18 9 views
11

एक और सवाल का जवाब है, मैं निम्न उदाहरण के बारे में सोचा:सी अलियासिंग नियमों और memcpy

void *p; 
unsigned x = 17; 

assert(sizeof(void*) >= sizeof(unsigned)); 
*(unsigned*)&p = 17;  // (1) 
memcpy(&p, &x, sizeof(x)); // (2) 

पंक्ति 1 टूटता नियम aliasing। लाइन 2, हालांकि, ठीक wrt है। एलियासिंग नियम। सवाल यह है: क्यों? क्या कंपाइलर में memcpy जैसे फ़ंक्शंस के बारे में विशेष अंतर्निहित ज्ञान है, या क्या ऐसे कुछ अन्य नियम हैं जो memcpy OK बनाते हैं? एलियासिंग नियमों को तोड़ने के बिना मानक सी में memcpy- जैसे कार्यों को लागू करने का कोई तरीका है?

उत्तर

13

सी मानक इस पर काफी स्पष्ट है। p नामक ऑब्जेक्ट का प्रभावी प्रकार void* है, क्योंकि इसमें घोषित प्रकार है, 6.5/6 देखें। सी 99 में एलियासिंग नियम और लिखने के लिए लागू होते हैं, और void* पर unsigned(1) में 6.5/7 के अनुसार अपरिभाषित व्यवहार है।

इसके विपरीत, (2) ठीक है, क्योंकि unsigned char* कोई ऑब्जेक्ट (6.5/7) उपनाम कर सकता है। मानक के रूप में

इस उपखंड में सभी कार्यों के लिए 7.21.2/1 पर memcpy परिभाषित करता है, हर किरदार में व्याख्या की जाएगी जैसे कि वह प्रकार अहस्ताक्षरित चार था (और इसलिए हर संभव वस्तु अभिव्यक्ति मान्य है और एक अलग महत्व है)।

memcpy फ़ंक्शन s1 द्वारा इंगित ऑब्जेक्ट में s2 द्वारा इंगित ऑब्जेक्ट से एन वर्णों की प्रतिलिपि बनाता है। अगर प्रतिलिपि बनाने वाली वस्तुओं के बीच प्रतिलिपि होती है, तो व्यवहार अव्यवस्थित है।

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


में ठीक है सी ++ स्टैंडर्ड है, जो मेरी राय में इस मुद्दे पर स्पष्ट से दूर है के अनुसार, मुझे लगता है कि निम्नलिखित रखती है। कृपया इस व्याख्या को एकमात्र संभव न लें - अस्पष्ट/अपूर्ण विनिर्देश अटकलों के लिए बहुत सारे कमरे को छोड़ देता है।

रेखा (1) समस्याग्रस्त है क्योंकि &p का संरेखण unsigned प्रकार के लिए ठीक नहीं हो सकता है। यह p में unsigned int होने के लिए संग्रहीत ऑब्जेक्ट के प्रकार को बदलता है। जब तक आप p के माध्यम से उस ऑब्जेक्ट को बाद में एक्सेस नहीं करते हैं, तब तक एलियासिंग नियम टूटा नहीं जाता है, लेकिन संरेखण आवश्यकताएं अभी भी हो सकती हैं।

लाइन (2) लेकिन कोई संरेखण समस्या है, और के रूप में आप एक void*, जो कैसे void* प्रकार संग्रहीत bitpattern की व्याख्या के आधार पर अपरिभाषित व्यवहार के कारण हो सकता के रूप में बाद में p उपयोग न कर लें, तब तक इस प्रकार मान्य है। मुझे नहीं लगता कि इस प्रकार वस्तु का प्रकार बदल गया है।

एक लंबा GCC Bugreport है जो इस तरह के कलाकारों के परिणामस्वरूप एक सूचक के माध्यम से लिखने के प्रभावों पर चर्चा करता है और प्लेसमेंट के लिए क्या अंतर होता है (उस सूची में लोग इस बात से सहमत नहीं हैं)।

+0

कृपया मार्सेलो के जवाब पर टिप्पणी में प्रश्न देखें। उस पर कोई टिप्पणी? – zvrba

+1

@zvrba, ओह कुछ भी अलग नहीं है। आप बस 'शून्य *' के बीच में डाले गए हैं, जो सीधे कास्टिंग के बराबर है। यदि आप memcpy "अनुकरण" करना चाहते हैं, तो आपको इसे 'हस्ताक्षरित char * पीसी = (हस्ताक्षरित char *) और p, * i = (unsigned char *) और x; * पीसी = * एक्स; * पीसी ++ = * एक्स ++; ... ', जो यह करता है। –

+0

क्या memptpy() को शामिल किया गया ऑब्जेक्ट्स 'ओवरलैप' माना जाता है यदि srcptr और destptr बराबर हैं, या क्या कोई ऐसी भाषा है जो स्पष्ट रूप से उस परिदृश्य को अनुमति देगी? – supercat

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