2012-01-02 17 views
7

हम दो structs है मान लीजिए:Struct सूचक अनुकूलता

typedef struct Struct1 
{ 
    short a_short; 
    int id; 
} Struct1; 

typedef struct Struct2 
{ 
    short a_short; 
    int id; 
    short another_short; 
} Struct2; 

यह Struct1 * को Struct2 * से कास्ट करने के लिए सुरक्षित है? एएनएसआई स्पेक इस बारे में क्या कहता है? मुझे पता है कि कुछ कंप्यूटर्स के पास मेमोरी उपयोग को अनुकूलित करने के लिए structs फ़ील्ड को पुन: व्यवस्थित करने का विकल्प होता है, जो दो structs को असंगत रूप से प्रस्तुत कर सकता है। क्या यह सुनिश्चित करने का कोई तरीका है कि संकलक ध्वज के बावजूद यह कोड मान्य होगा?

धन्यवाद!

+2

* रिकॉर्डिंग * सदस्यों को मानक AFAIK द्वारा अनुमति नहीं है। मेरा मानना ​​है कि पैडिंग की अलग-अलग मात्रा डालने की अनुमति होगी हालांकि। – delnan

+0

@ डेलन ओह तो फिर उस स्ट्रक्चर 'पैकिंग' केवल संरेखण अक्षम कर देगा? धन्यवाद, मुझे यह नहीं पता था! – Waneck

उत्तर

5

struct संकेत प्रकार हमेशा

(C99, 6.2.5p27) सी में एक ही प्रतिनिधित्व "सभी संकेत प्रकार एक दूसरे के रूप में ही प्रतिनिधित्व और संरेखण आवश्यकताओं होगा की संरचना करने के।"

और संरचना प्रकार में सदस्यों सी में क्रम में हमेशा से रहे हैं

(C99, 6.7.2.1p5) "एक संरचना एक प्रकार सदस्यों में से एक दृश्य से मिलकर, जिनकी भंडारण आवंटित किया जाता है है एक क्रमबद्ध अनुक्रम में "

+1

यह सवाल का जवाब नहीं देता है; इन बाधाओं के साथ भी यह एक अलियासिंग उल्लंघन हो सकता है। हालांकि, कुछ स्थितियों के तहत, सी मानक स्पष्ट रूप से ओपी चाहता है कि अनुमति देता है। –

+0

एएनएसआई स्पेक से इन उद्धरणों के लिए आपका बहुत बहुत धन्यवाद। यह मेरे लिए यह स्पष्ट करता है कि यह सुरक्षित है! – Waneck

+0

@ आर। क्या स्थितियां? – Waneck

2

यह शायद सबसे अधिक काम करेगा। लेकिन आप यह पूछने में बहुत सही हैं कि आप कैसे सुनिश्चित कर सकते हैं कि यह कोड मान्य होगा। तो: कहीं भी आपके प्रोग्राम (स्टार्टअप पर) एएसएसईआरटी स्टेटमेंट्स का एक गुच्छा एम्बेड करें जो सुनिश्चित करता है कि offsetof(Struct1.a_short)offsetof(Struct2.a_short) आदि के बराबर है। इसके अलावा, आपके अलावा कुछ प्रोग्रामर इन दिनों में से किसी एक संरचना को संशोधित कर सकते हैं लेकिन दूसरे नहीं क्षमा से सुरक्षित

+0

स्थिर आवेषण का उपयोग करना बेहतर होगा ... –

+0

धन्यवाद माइक, मैं निश्चित रूप से यह सुनिश्चित करने के लिए कुछ आवेदक जोड़ूंगा! – Waneck

+0

@ आर .. स्थिर आवेषण? मुझे नहीं पता था कि वे अस्तित्व में हैं।[मैंने इसे देखा और पाया] [http://stackoverflow.com/questions/3385515/static-assert-in-c)। तुम सही हो, धन्यवाद। –

3

यह सुरक्षित है, जहां तक ​​मुझे पता है।

लेकिन यह अभी तक बेहतर, यदि संभव हो तो है, ऐसा करने के लिए:

typedef struct { 
    Struct1 struct1; 
    short another_short; 
} Struct2; 

तो फिर तुम संकलक भी बता दिया है कि Struct1 का एक उदाहरण के साथ शुरू होता है Struct2, और के बाद से एक struct के लिए सूचक हमेशा कम से बताते हैं अपने पहला सदस्य, Struct1 * के रूप में Struct2 * का इलाज करने के लिए आप सुरक्षित हैं।

+0

अच्छी तरह से, यदि एक दिन का ऑफसेट (स्ट्रक्चर 1.ए_शॉर्ट) 'पाया जाएगा तो थोड़ा सा मौका मिलेगा ऑफसेट (स्ट्रक्चर 2.ए_शॉर्ट) 'के बराबर नहीं है, फिर एक दिन की ऑफसेट (स्ट्रक्चर 2.स्ट्रक्चर 1) 'शून्य के बराबर नहीं मिलेगी। (जिसका अर्थ है कि '& struct2! = (स्ट्रक्चर 2 *) और struct2.struct1')। –

+0

दरअसल, इस तरह से बहुत बेहतर है! :) धन्यवाद! – Waneck

+0

यदि स्ट्रक्चर 1 और स्ट्रक्चर 2 ने "int" को पहले और "int" को 32-बिट संरेखण की आवश्यकता है, तो दोनों संरचना प्रकार 8 बाइट्स हो सकते हैं, लेकिन स्ट्रक्चर 2 के आपके वैकल्पिक रूप में 12 बाइट्स की आवश्यकता होगी। यदि कंपाइलर्स सामान्य प्रारंभिक अनुक्रम नियम का सम्मान करते हैं, तो कोई भी फॉर्म मान्य होना चाहिए (और 8-बाइट फॉर्म अधिक कुशल होगा), लेकिन सी 8 9 मोड में जब भी लागू किया जाता है, तो जीसीसी अब सी 8 9 की गारंटी को बरकरार रखता है, सिवाय इसके कि '-फनो-सख्त- aliasing' झंडा का उपयोग किया जाता है। – supercat

1

हां, ऐसा करना ठीक है!

एक नमूना कार्यक्रम निम्नानुसार है।

#include <stdio.h> 

typedef struct Struct1 
{ 
    short a_short; 
    int id; 
} Struct1; 

typedef struct Struct2 
{ 
    short a_short; 
    int id; 
    short another_short; 
} Struct2; 

int main(void) 
{ 

    Struct2 s2 = {1, 2, 3}; 
    Struct1 *ptr = &s2; 
    void *vp = &s2; 
    Struct1 *s1ptr = (Struct1 *)vp; 

    printf("%d, %d \n", ptr->a_short, ptr->id); 
    printf("%d, %d \n", s1ptr->a_short, s1ptr->id); 

    return 0; 
}