2014-11-08 3 views
5

मेरे पास एक सी प्रोजेक्ट है जिसे विभिन्न (पीसी और एम्बेडेड) प्लेटफॉर्म पर पोर्टेबल बनाने के लिए डिज़ाइन किया गया है।मैं सामान्य हेडर में कार्यान्वयन-परिभाषित संरचना को कैसे टाइप करूं?

एप्लिकेशन कोड विभिन्न कॉल का उपयोग करेगा जिसमें प्लेटफ़ॉर्म-विशिष्ट कार्यान्वयन होंगे, लेकिन पोर्टेबिलिटी में सहायता के लिए एक सामान्य (सामान्य) API साझा करें। मैं फ़ंक्शन प्रोटोटाइप और संरचनाओं को घोषित करने के सबसे उचित तरीके से निपटने की कोशिश कर रहा हूं।

यहाँ क्या मैं अब तक लेकर आए हैं:

main.c:

#include "generic.h" 

int main (int argc, char *argv[]) { 
    int ret; 
    gen_t *data; 

    ret = foo(data); 
    ... 
} 

generic.h: (मंच-नास्तिक शामिल)

typedef struct impl_t gen_t; 

int foo (gen_t *data); 

impl.h: (प्लेटफ़ॉर्म-विशिष्ट घोषणा)

#include "generic.h" 

typedef struct impl_t { 
    /* ... */ 
} gen_t; 

impl.c: (प्लेटफ़ॉर्म-विशिष्ट कार्यान्वयन)

int foo (gen_t *data) { 
    ... 
} 

बिल्ड:

gcc -c -fPIC -o platform.o impl.c 
gcc -o app main.c platform.o 

अब, यह काम करने के लिए ... में है कि यह संकलित प्रकट होता है ठीक। हालांकि, मैं आमतौर पर अपने संरचनाओं को टैग नहीं करता क्योंकि उन्हें typedef 'डी उपनाम के बाहर कभी भी एक्सेस नहीं किया जाता है। यह एक छोटा सा नाइट-पिक है, लेकिन मुझे आश्चर्य है कि अज्ञात structs के साथ एक ही प्रभाव प्राप्त करने का कोई तरीका है?

मैं भी भावी पीढ़ी के लिए पूछ रहा हूँ, के बाद से मैं थोड़ी देर के लिए खोज की है और निकटतम जवाब मैंने पाया यह था: (Link)

मेरे मामले में, यह सही तरीका नहीं हो सकता है, आवेदन के रूप में विशेष रूप से कभी भी कार्यान्वयन शीर्षलेखों को सीधे शामिल नहीं करना चाहिए - संपूर्ण बिंदु प्लेटफ़ॉर्म से प्रोग्राम को डीक्यूपल करना है।

मैं दूसरे से कम आदर्श तरीके के एक जोड़े इसका समाधान करने के देखते हैं, उदाहरण के लिए:

generic.h:

#ifdef PLATFORM_X 
#include "platform_x/impl.h" 
#endif 

/* or */ 

int foo (struct impl_t *data); 
न तो इनमें से

विशेष रूप से आकर्षक लगता है, और निश्चित रूप से नहीं मेरी शैली। जबकि मैं अपस्ट्रीम तैरना नहीं चाहता हूं, मैं भी विरोधाभासी शैली नहीं चाहता हूं जब मेरे मन में ठीक से लागू करने के लिए एक अच्छा तरीका हो सकता है। तो मुझे लगता है कि टाइपपीफ समाधान सही रास्ते पर है, और यह केवल स्ट्रक्चर टैग बैगेज है जिसके साथ मुझे छोड़ा गया है।

विचार?

+0

आप केवल 'gen_t' को पॉइंटर प्रकार (एक हैंडल) बना सकते हैं। फिर ग्राहकों को इसे शुरू/उपयोग/नष्ट करने के लिए अपने एपीआई का उपयोग करना होगा। या थोड़ी भिन्नता, अपनी सार्वजनिक रूप से उजागर संरचना में वास्तविक कार्यान्वयन के लिए एक अपारदर्शी सूचक शामिल है। अन्यथा, आप और कुछ नहीं कर सकते हैं। एक ऑब्जेक्ट या जिस तरह से ट्रैक किया जाना चाहिए उसे क्लाइंट को जानना होगा। –

+0

इसमें कोई समस्या है कि generic.h को impl.h.h से पहले शामिल किया जा रहा है। लेकिन, generic.h impl.h.E. में परिभाषित संरचना का संदर्भ दे रहा है। एक आगे संदर्भ। (संभवतः संकलित नहीं होगा) जेनेरिक में बहुत बेहतर है। impl.h शामिल करें (जहां impl.h प्लेटफॉर्म विशिष्ट है) तो जेनेरिक.h इसका उपयोग करने का प्रयास करते समय संरचना पहले ही परिभाषित की जाएगी। – user3629249

+1

संरचना के रूप में परिभाषित करना कहीं बेहतर है: struct tagname {;;; }; फिर हमेशा इसे 'struct tagname myname' के रूप में संदर्भित करें; इसके लिए कई कारण हैं: 1) नामित structs एक अवमूल्यन प्रारूप है 2) डिबगर्स टैग फ़ील्ड का संदर्भ फ़ील्ड का उपयोग करते हैं, आदि 3) एक स्ट्रक्चर पर टाइपपीफ का उपयोग करना (सामान्य रूप से) खराब प्रोग्रामिंग अभ्यास – user3629249

उत्तर

4

आपकी वर्तमान तकनीक सही है। अज्ञात (untagged) struct का उपयोग करने का प्रयास करने से आप जो भी करने का प्रयास कर रहे हैं उसे हरा देता है - आपको हर जगह struct की परिभाषा के विवरण का खुलासा करना होगा, जिसका अर्थ है कि अब आपके पास अपारदर्शी डेटा प्रकार नहीं है।


एक comment में, user3629249 ने कहा:

हेडर फाइल समावेशन के आदेश का मतलब है generic.h फ़ाइल से struct करने के लिए एक आगे संदर्भ नहीं है; अर्थात, संरचना परिभाषित होने से पहले, इसका उपयोग किया जाता है। यह असंभव है कि यह संकलित होगा।

यह अवलोकन प्रश्न में दिखाए गए शीर्षलेखों के लिए गलत है; यह नमूना main() कोड के लिए सटीक है (जिसे मैंने इस प्रतिक्रिया को जोड़ने तक नहीं देखा था)।

मुख्य बिंदु यह है कि इंटरफ़ेस फ़ंक्शंस gen_t प्रकार पर पॉइंटर्स लेते हैं या वापस करते हैं, जो बदले में struct impl_t पॉइंटर पर मानचित्र होते हैं। जब तक क्लाइंट कोड को संरचना के लिए स्थान आवंटित करने की आवश्यकता नहीं होती है, या ढांचे को किसी संरचना के सदस्य तक पहुंचने के लिए संरचना के लिए एक पॉइंटर की आवश्यकता नहीं होती है, तो क्लाइंट कोड को संरचना के विवरण जानने की आवश्यकता नहीं होती है। मौजूदा प्रकार के रूप में घोषित संरचना प्रकार के लिए पर्याप्त है। आप struct impl_t के अस्तित्व की घोषणा करने के इन दोनों में से इस्तेमाल कर सकते हैं:

struct impl_t; 

typedef struct impl_t gen_t; 

बाद भी प्रकार struct impl_t के लिए उर्फ ​​gen_t परिचय देता है। भी Which part of the C standard allows this code to compile? और Does the C standard consider that there are one or two struct uperms entry types in this header?

प्रश्न में मूल main() कार्यक्रम था देखें:

int main (int argc, char *argv[]) { 
    int ret; 
    gen_t data; 

    ret = foo(&data); 
    … 
} 

इस कोड को एक अपारदर्शी (गैर सूचक) के रूप में gen_t साथ संकलित नहीं किया जा सकता टाइप करें।

typedef struct impl_t *gen_t; 

यह साथ संकलन नहीं होगा: यह ठीक से काम करेगा

typedef struct impl_t gen_t; 

क्योंकि संकलक पता होना चाहिए कि बड़ी संरचना data के लिए सही जगह आवंटित करने के लिए है, लेकिन संकलक कि पता नहीं कर सकते हैं एक अपारदर्शी प्रकार क्या है इसकी परिभाषा के अनुसार आकार। (संरचनाओं की ओर इशारा typedefing के लिए Is it a good idea to typedef pointers? देखें।)

इस प्रकार, main() कोड होना चाहिए और अधिक की तरह:

#include "generic.h" 

int main(int argc, char **argv) 
{ 
    gen_t *data = bar(argc, argv); 
    int ret = foo(data); 
    ... 
} 

जहां (इस उदाहरण के लिए) bar(), extern gen_t *bar(int argc, char **argv); के रूप में परिभाषित किया गया है, तो यह करने के लिए एक सूचक रिटर्न अपारदर्शी प्रकार gen_t

राय इस बात पर विभाजित है कि क्या हमेशा struct tagname का उपयोग करना बेहतर है या नाम के लिए typedef का उपयोग करना बेहतर है। लिनक्स कर्नेल कोड का एक बड़ा निकाय है जो typedef तंत्र का उपयोग नहीं करता है; सभी संरचनाएं स्पष्ट रूप से struct tagname हैं। दूसरी ओर, सी ++ स्पष्ट typedef की आवश्यकता से दूर है; लेखन:

struct impl_t; 
एक सी ++ प्रोग्राम में

मतलब यह है कि नाम अब एक प्रकार का नाम है।चूंकि अपारदर्शी संरचना प्रकारों को एक टैग की आवश्यकता होती है (या आप void * का उपयोग करके सबकुछ के लिए समाप्त हो जाते हैं, जो कि कारणों की पूरी श्रृंखला के लिए बुरा है, लेकिन प्राथमिक कारण यह है कि आप void * का उपयोग करके सभी प्रकार की सुरक्षा खो देते हैं; याद रखें, typedef अंतर्निहित के लिए उपनाम प्रस्तुत करता है प्रकार, नहीं एक नया अलग प्रकार), सी में जिस तरह से मैं कोड सी simulates ++:

typedef struct Generic Generic; 

मैं अपने प्रकार पर _t प्रत्यय का उपयोग कर, क्योंकि POSIX कार्यान्वयन के लिए _t सुरक्षित रखता है उपयोग करने के लिए * (यह भी देखें बचने What does a type followed by _t represent?)। आप भाग्यशाली हो सकते हैं और इससे दूर हो सकते हैं। मैंने कोड बेस पर काम किया है जहां dec_t और loc_t जैसे प्रकार कोड बेस द्वारा परिभाषित किए गए थे (जो कार्यान्वयन का हिस्सा नहीं था - जहां 'कार्यान्वयन' का मतलब सी संकलक और इसका सहायक कोड है, या सी लाइब्रेरी और इसका सहायक कोड), और उन दोनों प्रकारों ने दशकों तक दर्द का कारण बना दिया क्योंकि कुछ सिस्टम जहां कोड को पोर्ट किया गया था, उन प्रकारों को परिभाषित किया गया था, जैसा कि सिस्टम का विशेषाधिकार है। उन नामों में से एक जिन्हें मैं छुटकारा पाने में कामयाब रहा; दूसरा मैंने नहीं किया। 'दर्दनाक दर्द! यदि आपको _t का उपयोग करना चाहिए (यह इंगित करने का एक सुविधाजनक तरीका है कि कुछ एक प्रकार है), तो मैं कुछ विशिष्ट 0f, उदाहरण के लिए pqr_typename_t का एक विशिष्ट उपसर्ग का उपयोग करने की सलाह देता हूं।

* POSIX मानक में The Name Space में दूसरी तालिका की निचली पंक्ति देखें।

+0

शीर्षलेख का क्रम है फ़ाइल समावेशन का अर्थ है जेनेरिक.h फ़ाइल, आईई द्वारा संरचना के लिए एक आगे संदर्भ है संरचना परिभाषित होने से पहले, इसका उपयोग किया जाता है। यह असंभव है कि यह – user3629249

+0

संकलित करेगा यह एक उत्कृष्ट उत्तर है जो मुझे हर चीज को साफ़ करता है। धन्यवाद! बीटीडब्ल्यू, आप मुख्य() में gen_t उपयोग के बारे में बिल्कुल सही हैं। मैंने इसे न्यूनतम प्रासंगिक कोड पर फिसल दिया और उस भाग को अनुवाद में छोड़ दिया। सूचक पर उपयोग किया जाने वाला पहला फ़ंक्शन कॉल कार्यान्वयन का हिस्सा है, जो इसके सटीक आकार को जानता है, और आवश्यकतानुसार स्मृति आवंटित करता है। अंत में, _t प्रत्यय पर हेड-अप के लिए धन्यवाद। मुझे इसके बारे में पता नहीं था - औपचारिक रूप से प्रशिक्षित नहीं होने के डाउनसाइड्स में से एक। – SirNickity

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