2015-01-09 5 views
31

कुछ कोड मैंने महसूस किया कि निम्न कोड को संकलित करता है की कोशिश कर रहा:सी में अज्ञात संरचना कैसे वापस करें?

struct { int x, y; } foo(void) { 
} 

ऐसा लगता है मानो हम foo जो एक गुमनाम struct रिटर्न नाम के एक समारोह को परिभाषित कर रहे हैं।

अब, मेरा सवाल है: क्या यह केवल मेरे कंपाइलर के साथ संकलित होता है या यह कानूनी सी (99) है? यदि हां, तो रिटर्न स्टेटमेंट के लिए सही वाक्यविन्यास क्या है और मैं एक वैरिएबल में लौटाए गए मान को सही तरीके से कैसे निर्दिष्ट कर सकता हूं?

+0

यह की तरह लगता है सख्त यह त्रुटि दे रहा है gcc.With C99 के कुछ हैक http://ideone.com/665vM2 – Ankur

+4

@Shan: फ़ंक्शन परिभाषा वाक्यविन्यास अभी भी कानूनी है। यह केवल गायब रिटर्न स्टेटमेंट के बारे में शिकायत करता है (और मेरा प्रश्न पूछता है कि इस स्थिति में सही रिटर्न स्टेटमेंट कैसे करें)। – Askaga

+0

सी 99 में अज्ञात structs जैसी कोई बात नहीं है। आप _compound literal_ बना सकते हैं लेकिन उनके पास हमेशा स्थानीय दायरा होता है। – Lundin

उत्तर

23

जो संरचना आप लौट रहे हैं वह अज्ञात संरचना नहीं है। सी मानक एक अज्ञात संरचना को किसी अन्य संरचना के सदस्य के रूप में परिभाषित करता है जो टैग का उपयोग नहीं करता है। आप जो भी लौट रहे हैं वह एक टैग के बिना एक संरचना है, लेकिन चूंकि यह सदस्य नहीं है, यह अज्ञात नहीं है। टैग के बिना संरचना को इंगित करने के लिए जीसीसी < अज्ञात> नाम का उपयोग करता है।

मान लें कि आप फ़ंक्शन में एक समान संरचना घोषित करने का प्रयास करते हैं।

struct { int x, y; } foo(void) 
{ 
    return (struct { int x, y; }){ 0 } ; 
} 

जीसीसी इसके बारे में शिकायत: जब प्रकार लौटने असंगत प्रकार '< गुमनाम struct>' लेकिन 'struct < गुमनाम>' उम्मीद थी

जाहिर प्रकार संगत नहीं हैं। स्टैंडर्ड में देख रहे हैं हम देखते हैं कि:

6.2.7 संगत प्रकार और समग्र प्रकार

1: दो प्रकार संगत प्रकार है अगर उनके प्रकार एक ही हैं। यह निर्धारित करने के लिए अतिरिक्त नियम हैं कि दो प्रकार के संगत हैं टाइप प्रकार विनिर्देशकों के लिए 6.7.2 में, टाइप क्वालीफायर के लिए 6.7.3 में, और घोषणाकर्ताओं के लिए 6.7.6 में वर्णित हैं। इसके अलावा, अलग-अलग अनुवाद इकाइयों में घोषित दो संरचना, संघ, या समेकित प्रकार संगत हैं यदि उनके टैग और सदस्य निम्न आवश्यकताओं को पूरा करते हैं: यदि किसी को टैग के साथ घोषित किया जाता है, तो दूसरे को एक ही टैग के साथ घोषित किया जाएगा।यदि दोनों अपनी संबंधित अनुवाद इकाइयों के भीतर कहीं भी पूरा हो जाते हैं, तो निम्नलिखित अतिरिक्त आवश्यकताएं लागू होती हैं: उनके सदस्यों के बीच एक-एक-एक पत्राचार होगा कि संबंधित सदस्यों की प्रत्येक जोड़ी संगत प्रकारों के साथ घोषित की जाती है; यदि जोड़ी के एक सदस्य को संरेखण विनिर्देशक के साथ घोषित किया जाता है, तो दूसरे को समकक्ष संरेखण विनिर्देशक के साथ घोषित किया जाता है; और यदि जोड़ी के एक सदस्य को नाम के साथ घोषित किया जाता है, तो दूसरे को उसी नाम से घोषित किया जाता है। दो संरचनाओं के लिए, संबंधित सदस्यों को उसी क्रम में घोषित किया जाएगा। दो संरचनाओं या संघों के लिए, संबंधित बिट-फ़ील्ड में समान चौड़ाई होगी। दो गणनाओं के लिए, संबंधित सदस्यों के समान मूल्य होंगे।

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

:

इसके बाद से यदि आप एक struct घोषित करने और इस समारोह में इसका इस्तेमाल करते हैं, तो आप एक टैग है, जो नियम है कि दोनों structs ही टैग करना है का उल्लंघन करता है का उपयोग करने के कोड सही बनाने के लिए असंभव है

struct t { int x, y; } ; 

struct { int x, y; } foo(void) 
{ 
    struct t var = { 0 } ; 

return var ; 
} 

फिर जीसीसी की शिकायत: असंगत प्रकार जब प्रकार 'struct टी', लेकिन लौटने 'struct < गुमनाम>' उम्मीद थी

+0

हम्म, दिलचस्प मैंने पहले मानक के उस हिस्से को कभी नहीं पढ़ा। "दो प्रकार के संगत प्रकार होते हैं यदि उनके प्रकार समान हैं" मेरे लिए पूर्ण बकवास जैसा लगता है (और यह इस स्थिति पर लागू हो सकता है; कौन जानता है), लेकिन यही वह नहीं है जिसे मैं टिप्पणी करना चाहता हूं। क्या मैं निष्कर्ष निकाल सकता हूं कि यद्यपि आपके उदाहरण में दो प्रकार संगत नहीं हैं, लेकिन वे ** ** ** एक अलग अनुवाद इकाई में परिभाषित एक समान प्रकार के साथ संगत होंगे? और इसलिए संगतता एक संक्रमणीय संबंध नहीं है? –

+0

@MarcvanLeeuwen प्रकार हालांकि बहुत सारे अपवादों के साथ समान होना चाहिए। विभिन्न अनुवाद इकाइयों में परिभाषित किए गए टैग के बिना स्ट्रक्चर संगत होंगे। – 2501

8

आप शायद नहीं कर सकते स्पष्टreturn अपने कार्य से कुछ कुल मूल्य (जब तक आप एक typeof एक्सटेंशन का उपयोग परिणाम के प्रकार के प्राप्त करने के लिए)।

कहानी का नैतिक कि भले ही आप फ़ंक्शन घोषणा कर सकते हैं एक गुमनामstruct आप व्यावहारिक रूप सेकि कभी नहीं करना चाहिए है।

इसके बजाय, नाम struct और कोड:

struct twoints_st { int x; int y; }; 
struct twoints_st foo (void) { 
    return ((struct twoints_st) {2, 3}); 
}; 

सूचना है कि यह वाक्य रचना ठीक है, लेकिन निष्पादन पर आम तौर पर अपरिभाषित व्यवहार, return बिना एक समारोह के लिए (उदाहरण के लिए आप exit इसके अंदर कह सकते हैं)। लेकिन आप (शायद कानूनी) कोड क्यों करना चाहते हैं:

struct { int xx; int yy; } bizarrefoo(void) { exit(EXIT_FAILURE); } 
12

यह जीसीसी के मेरे संस्करण में काम करता है, लेकिन कुल हैक की तरह लगता है। शायद ऑटो-जेनरेट कोड में उपयोगी जहां आप अद्वितीय संरचना टैग उत्पन्न करने की अतिरिक्त जटिलता से निपटना नहीं चाहते हैं, लेकिन मैं उस तर्कसंगतता के साथ आने के लिए खींच रहा हूं।

struct { int x,y; } 
foo(void) { 
    typeof(foo()) ret; 
    ret.x = 1; 
    ret.y = 10; 
    return ret; 
} 

main() 
{ 
    typeof(foo()) A; 

    A = foo(); 

    printf("%d %d\n", A.x, A.y); 
} 

इसके अलावा, यह typeof पर निर्भर है() है संकलक में मौजूद होने - जीसीसी और LLVM इसे समर्थन लगते हैं, लेकिन मुझे यकीन है कि कई compilers नहीं कर रहा हूँ।

+1

यह तकनीक आपके विचार से कहीं अधिक उचित हो सकती है। देखें कैसे डी भाषा इसके लिए सुविधाजनक वाक्यविन्यास है: [https://dpaste.dzfl.pl/c5880e348812](https://dpaste.dzfl.pl/c5880e348812) – Cauterite

1

यह जीसीसी के नवीनतम संस्करण तक काम करता है। मैक्रोज़ के साथ गतिशील सरणी बनाने के लिए यह विशेष रूप से उपयोगी है। उदाहरण के लिए:

#define ARRAY_DECL(name, type) struct { int count; type *array; } name 

तो फिर तुम realloc के साथ सरणी बना सकते हैं, आदि यह उपयोगी है क्योंकि तब आप किसी भी प्रकार के साथ एक गतिशील सरणी बना सकते हैं, और वहाँ उन सभी को बनाने के लिए एक तरीका है। अन्यथा आप void * के बहुत से उपयोग करके समाप्त कर देंगे और फिर कार्यों को लिखने के लिए वास्तव में मूल्यों को वापस और साथ प्राप्त कर सकते हैं। आप मैक्रोज़ के साथ यह सब शॉर्टकट कर सकते हैं; वह उनकी सुंदरता है।

0

या आप अनंत प्रत्यावर्तन बना सकते हैं:

struct { int x, y; } foo(void) { 
    return foo(); 
} 

कौन सा मुझे लगता है कि पूरी तरह से कानूनी है।

+0

कैसे struct प्रकार के सूचक के लौटने के बारे में? पहले आमंत्रण पर, कुछ स्मृति को मॉलोक करें और वैश्विक शून्य में एक सूचक को स्टोर करें *। उसके बाद, बस वैश्विक शून्य * वापस करें। मुझे लगता है कि अगर कोई ऐसा करता है तो वह वास्तव में घोषित प्रकार का उपयोग कर सकता है। – supercat

0

सी ++ 14 में अज्ञात structs को वापस करने का कोई तरीका है जो मैंने अभी खोजा है।
(सी ++ 11 पर्याप्त होना चाहिए, मुझे लगता है)
मेरे मामले में एक समारोह में intersect() रिटर्न std::pair<bool, Point> जो बहुत वर्णनात्मक नहीं है तो मैं परिणाम के लिए एक कस्टम प्रकार बनाने का फैसला किया।
मैं अलग struct बना सकता था लेकिन यह उचित नहीं था क्योंकि मुझे केवल इस विशेष मामले के लिए इसकी आवश्यकता होगी; यही कारण है कि मैंने एक अज्ञात संरचना का उपयोग किया।

auto intersect(...params...) { 
    struct 
    { 
     Point point; 
     bool intersects = false; 
    } result; 

    // do stuff... 

    return result; 
} 

और अब, बदसूरत

if (intersection_result.first) { 
    Point p = intersection_result.second 

के बजाय मैं बहुत बेहतर की तलाश में उपयोग कर सकते हैं:

if (intersection_result.intersects) { 
    Point p = intersection_result.point; 
+0

प्रश्न सी सी ++ के बारे में है। – Ruslan

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