2013-11-04 4 views
59

मैं अभी भी काम पर एक और कोड आधार पर आया हूं जहां डेवलपर्स स्ट्रक्चर के बजाए प्रतिलिपि/तुलना/सेटिंग करते समय लगातार structs के पहले तत्व के पते का उपयोग करते हैं। यहां एक साधारण उदाहरण है।संरचना के बजाय तत्व के पहले तत्व का पता क्यों उपयोग करें?

void bar(foo_t *inp) 
{ 
    foo_t l; 
    ... 
    memcpy(&l.a, &inp->a, sizeof(foo_t)); 
    ... 
} 

मैं अपने आप को कि रास्ते में memcpy के लिए एक कॉल लिख नहीं होगा:

typedef struct { 
    int a; 
    int b; 
} foo_t; 

तो फिर वहाँ एक समारोह है कि इस तरह के एक struct की एक प्रतिलिपि बनाता है:

पहले वहाँ एक struct प्रकार है और मैंने संदेह के साथ शुरुआत की कि मूल डेवलपर्स ने सी में काफी पॉइंटर्स और structs को समझ नहीं लिया है। हालांकि, अब मैंने इसे दो असंबद्ध कोड अड्डों में देखा है, बिना किसी सामान्य डेवलपर्स के साथ, इसलिए मैं खुद को संदेह करना शुरू कर रहा हूं।

कोई इस शैली का उपयोग क्यों करना चाहेगा?

+15

नीचे दिए गए कोई भी जवाब वास्तव में सी के मेरे ज्ञान में कुछ भी नहीं जोड़ा गया था, जिस तरह से मैं उम्मीद कर रहा था;) – Magnus

+6

यह बहुत उपयोगी है जब विशेष रूप से कई प्रकार की संरचना उसी तत्व के साथ शुरू होती है, जैसे कि छद्म विरासत। सीपीथन कोडबेस इसका उपयोग 'पायओब्जेक्ट' के साथ भारी रूप से करता है; सभी पायथन ऑब्जेक्ट्स 'पायओब्जेक्ट' सदस्य से शुरू होते हैं, और वे आमतौर पर 'पायओब्जेक्ट *' पॉइंटर्स के साथ पास हो जाते हैं, इसलिए आपको उस ऑब्जेक्ट के वास्तविक प्रकार को हार्डकोड करने की आवश्यकता नहीं है जिसके साथ आप काम कर रहे हैं। – user2357112

+1

'memcpy' सुरक्षित हो जाता है यदि यह अंतिम तर्क है:' sizeof (foo_t) - ऑफ़सेट (foo_t, a) '। –

उत्तर

61

कोई भी ऐसा नहीं करना चाहिए। यदि आप संरचना सदस्यों को पुनर्व्यवस्थित करते हैं तो आप परेशानी में हैं।

16

कोई नहीं होगा। यदि आपने कभी भी संरचना में a स्थानांतरित किया है या आपने सदस्य को पहले डाला है, तो आप मेमोरी स्मैशिंग बग पेश करेंगे।

60
इसके बजाय इस बात का

:

memcpy(&l.a, &inp->a, sizeof(foo_t)); 

आप ऐसा कर सकते हैं:

memcpy(&l, inp, sizeof(foo_t)); 

यह खतरनाक और भ्रामक हो सकता है, दोनों कथनों वास्तव में एक ही बात यहाँ कर के रूप में सी की गारंटी देता है वहाँ कोई गद्दी है पहले संरचना सदस्य से पहले।

l = *inp; 

क्यों एक इस शैली का उपयोग करना चाहते हैं:

लेकिन सबसे अच्छा बस एक साधारण असाइनमेंट ऑपरेटर का उपयोग कर संरचना वस्तुओं कॉपी करने के लिए है?

मेरा अनुमान: अज्ञानता या बुरा अनुशासन।

+8

+1। सुझाए गए दूरस्थ 2 सर्वश्रेष्ठ 'memcpy (& l, inp, sizeof l) '। – chux

+2

अज्ञानता? इतना यकीन नहीं है ... मेरा मतलब है, वे * जानते थे * (उम्मीद है कि) दोनों चीजें विनिर्देशन के बराबर और गारंटीकृत थीं इसलिए मुझे नहीं लगता कि आप उस कोड से * ज्ञान की कमी * का अनुमान लगा सकते हैं, लेकिन केवल एक * बुरा इस तरह के ज्ञान का उपयोग करें (जो अक्सर बदतर है!)। – Bakuriu

11

यह कोड असुरक्षित है क्योंकि संरचना के सदस्यों को पुन: व्यवस्थित करने के परिणामस्वरूप memcpy संरचना के सीमाओं से परे पहुंच सकता है यदि सदस्य a अब सदस्य नहीं है।

हालांकि, यह कल्पना है कि सदस्यों को जानबूझकर struct के भीतर का आदेश दिया जाता है और प्रोग्रामर उनमें से केवल एक सबसेट, सदस्य a साथ शुरुआत और struct के अंत तक चल नकल करना चाहता है। अगर ऐसी बात है तो कोड निम्न परिवर्तन के साथ सुरक्षित किया जा सकता है:

memcpy(&l.a, &inp->a, sizeof(foo_t) - offsetof(foo_t, a)); 

अब struct सदस्यों को किसी भी क्रम में पुन: व्यवस्थित किया जा सकता है और इस memcpy सीमा से बाहर जाना कभी नहीं होगा।

1

यह वास्तव में एक बुरी आदत है। उदाहरण के लिए, संरचना में एक और सदस्य प्रीपेड हो सकता है। यह एक बेहद लापरवाही आदत है और मुझे यह जानकर आश्चर्य हुआ कि कोई भी ऐसा करेगा।

अन्य ने पहले ही इन्हें नोट किया है; एक है कि कीड़े मुझे यह है:

struct Foo rgFoo [3]; 
struct Foo *pfoo = &rgFoo [0]; 

बजाय

struct Foo *pfoo = rgfoo; 
क्यों सूचकांक द्वारा सरणी deref

और उसके बाद का पता फिर से ले? यह पहले से ही पता है, नोट के फर्क सिर्फ इतना है कि pfoo तकनीकी रूप से है

struct Foo *const, 

नहीं

struct Foo *. 

अभी तक मैं पहले एक सब समय देखने के लिए प्रयोग किया जाता है।

1

दरअसल, इसके लिए एक वैध उपयोग केस है: कक्षा पदानुक्रम का निर्माण।

कक्षाओं के उदाहरण के रूप में structs का इलाज करते समय, पहला सदस्य (यानी ऑफसेट 0) आमतौर पर सुपरटेप उदाहरण होगा ... यदि एक सुपरटेप मौजूद है। यह उप-प्रकार बनाम सुपरटाइप का उपयोग करने के बीच एक साधारण कलाकार को स्थानांतरित करने की अनुमति देता है। बहुत उपयोगी।

इरादे के बारे में डैरेन स्टोन के नोट पर, यह सी 0 भाषा में ओओ निष्पादित करते समय अपेक्षित है।

किसी अन्य मामले में, मैं सुझाव दूंगा कि इस पैटर्न से बचने और सीधे सदस्य का उपयोग करने के कारण पहले से ही उद्धृत किए गए कारणों से।

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