2011-06-26 10 views
7

मान लें मैं एक नमूना स्रोत फ़ाइल, test.c है, जो मुझे बहुत पसंद है संकलन रहा है:सी पर काबू पाने अलियासिंग प्रतिबंध (? यूनियनों)

$ जीसीसी -03 -Wall

परीक्षण। ग कुछ इस तरह दिखता ..

/// CMP128(x, y) 
// 
// arguments 
// x - any pointer to an 128-bit int 
// y - any pointer to an 128-bit int 
// 
// returns -1, 0, or 1 if x is less than, equal to, or greater than y 
// 
#define CMP128(x, y) // magic goes here 

// example usages 

uint8_t A[16]; 
uint16_t B[8]; 
uint32_t C[4]; 
uint64_t D[2]; 
struct in6_addr E; 
uint8_t* F; 

// use CMP128 on any combination of pointers to 128-bit ints, i.e. 

CMP128(A, B); 
CMP128(&C[0], &D[0]); 
CMP128(&E, F); 

// and so on 

चलते भी कहते हैं कि मैं प्रतिबंध स्वीकार करते हैं कि अगर आप दो अतिव्यापी संकेत में गुजरती हैं, आप अपरिभाषित पुनः प्राप्त sults।

मैं कुछ इस तरह की कोशिश की है

#define CMP128(x, y) ({ 
    uint64_t* a = (void*)x; 
    uint64_t* b = (void*)y; 

    // compare a[0] with b[0], a[1] with b[1] 
}) 

(इन मैक्रो कल्पना ठीक से प्रत्येक पंक्ति के अंत में बैकस्लैश-एस्केप्ड नई-पंक्तियों के साथ स्वरूपित कर रहे हैं) लेकिन जब मैं भिन्नता मैक्रो में (एक [ 0] < बी [0]) मुझे जीसीसी

से त्रुटियों में "ड्रेफ्रेंसिंग ब्रेक सख्त-एलियासिंग नियम" त्रुटियां मिलती हैं, मैंने सोचा था कि आपको दो अलग-अलग तरीकों से स्मृति में एक ही स्थान को उचित रूप से संदर्भित करने के लिए यूनियनों का उपयोग करना था, इसलिए अगले मैंने कुछ कोशिश की जैसे

#define CMP128(x, y) ({ 
    union { 
     typeof(x) a; 
     typeof(y) b; 
     uint64_t* c; 
    } d = { .a = (x) } 
     , e = { .b = (y) }; 

    // compare d.c[0] with e.c[0], etc 
}) 

कि सिवाय मैं सख्त अलियासिंग नियमों के बारे में संकलक से ठीक उसी त्रुटियों मिलता है।

तो: क्या सख्त-एलियासिंग तोड़ने के बिना ऐसा करने का कोई तरीका है, वास्तव में की तुलना स्मृति? उपयोग memcmp यह करने के लिए:

संपादित करें (may_alias does not को गिनती, यह सिर्फ आप सख्त अलियासिंग नियम बायपास करने के लिए अनुमति देता है)। मैं अलियासिंग नियमों पर पकड़ा गया और इसके बारे में नहीं सोचा।

+1

मानक-अनुरूप तरीके से यूनियनों का उपयोग करने के लिए, आपको केवल उस सदस्य से पढ़ने की अनुमति है जिसे आपने पिछली बार लिखा था। –

+8

@ केरेक: सच नहीं - सी 99 यूनियनों के माध्यम से टाइप-पनिंग की अनुमति देता है, एक फुटनोट जो उल्लेख करता है कि यह स्पष्ट रूप से टीसी 3 के साथ जोड़ा गया था; हालांकि, टोड का कोड अभी भी गलत है ... – Christoph

+0

@ क्रिस्टोफ: सी 1 एक्स भी बेहतर है, परिशिष्ट जे (यूबी) तय किया गया है, अंतिम लिखित सदस्य से संबंधित बाइट पढ़ने की अनुमति देने के लिए (जो स्पष्ट रूप से सी 99 में उद्देश्य था, लेकिन स्पष्ट रूप से परिशिष्ट जे को तब अनदेखा किया गया था)। – ninjalj

उत्तर

5

कंपाइलर सही है क्योंकि एलियासिंग नियम किसी भी पॉइंटर जादू के बावजूद ऑब्जेक्ट (यानी स्मृति स्थान) के तथाकथित 'प्रभावी प्रकार' द्वारा निर्धारित किए जाते हैं। इस मामले में, यूनियन के साथ पॉइंटर्स टाइप-पनिंग एक स्पष्ट कलाकार से अलग नहीं है - कास्ट का उपयोग करना वास्तव में बेहतर है क्योंकि मानक गारंटी नहीं देता है कि आर्बिटरी पॉइंटर प्रकारों में संगत प्रतिनिधित्व होते हैं, यानी आप अनावश्यक रूप से क्रियान्वयन-परिभाषित के आधार पर हैं व्यवहार।

यदि आप मानक के अनुरूप होना चाहते हैं, तो आपको मूल चर की घोषणा के दौरान डेटा को नए चरों में कॉपी करने या संघ का उपयोग करने की आवश्यकता है।

यदि आपके 128-बिट पूर्णांक या तो बड़े-एंडियन या छोटे-एंडियन (यानी मिश्रित-एंडियन नहीं हैं) हैं, तो आप memcmp() (या तो सीधे या वापसी मूल्य को अस्वीकार करने के बाद) का उपयोग कर सकते हैं या बाइट-वार तुलना स्वयं कर सकते हैं : चरित्र प्रकार के पॉइंटर्स के माध्यम से पहुंच एलियासिंग नियम के लिए एक अपवाद है।

+1

मुझे memcmp के बारे में सोचना चाहिए था। यह मूल रूप से वही है जो मैं करना चाहता हूं। –

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