2017-06-13 12 views
16

के माध्यम से बच्चे को चर को एक्सेस करना अगर मैं इन संरचनाओं है: आप b.f.x के माध्यम से x का उपयोग होताउच्च स्तर संरचनाओं

typedef struct { int x; } foo; 
typedef struct { foo f; } bar; 
आम तौर पर

, लेकिन वहाँ इसे सेट अप करने, ताकि आप का जिक्र किए बिना तत्व x उपयोग कर सकते हैं एक तरीका है f?

bar b; 
b.x = ... 

मेरी पहली अंतर्ज्ञान है कि आप नहीं के बाद से वहाँ नाम संघर्ष के लिए एक संभावना है, तो दो उप संरचनाओं दोनों एक सदस्य एक्स थी और मैं समझ नहीं क्या संकलन त्रुटि हो जाएगा कर सकते हैं। हालांकि, मुझे कुछ ढांचे में काम करना याद है जहां यह संभव था।

C++ में मैं एक बार एक ढांचे में काम किया, जहां bar ही अस्तित्व में है, और आप एक अलग वर्ग से सदस्य चर के रूप में अपने सदस्यों this->x का उपयोग कर सकते हैं। मैं यह पता लगाने की कोशिश कर रहा हूं कि यह कैसे किया जा सकता है।

उत्तर

18

आप सी 11 के साथ कर सकते हैं:

§ 6.7.2.1 - 11

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

तो यह कोड पराक्रम काम:

#include <stdio.h> 

typedef struct { int x; } foo; 
typedef struct { foo; } bar; 

int main(void) 
{ 
    bar b; 
    b.x = 1; 
    printf("%d\n", b.x); 
} 

समस्या यहां है कि विभिन्न compilers पर कि क्या एक typedef कोई टैग के साथ एक struct विनिर्देशक के रूप में स्वीकार्य है मेरी परीक्षणों में सहमत नहीं है मानक निर्दिष्ट करता है:

§ 6.7।8 - 3

एक घोषणा जिसका भंडारण-वर्ग विनिर्देशक typedef है, प्रत्येक declarator एक पहचानकर्ता को परिभाषित करता है एक typedef नाम उस प्रकार रास्ते में पहचानकर्ता के लिए निर्दिष्ट 6.7.6 में वर्णित अर्थ है होना करने के लिए । [...]typedef घोषणा एक नए प्रकार का परिचय नहीं देती है, केवल निर्दिष्ट प्रकार के लिए समानार्थी शब्द।

(जोर मेरा) - लेकिन पर्याय भी एक typdef नाम विनिर्देशक मतलब है एक struct विनिर्देशक के लिए विनिमय है? gcc इसे स्वीकार करता है, clang नहीं करता है।

बेशक

, वहाँ इन घोषणाओं के साथ प्रकार foo के पूरे सदस्य व्यक्त करने के लिए, आप अपने नामित सदस्य f बलिदान कोई रास्ता नहीं है।

नाम टकराव के बारे में अपने संदेह के संबंध में, इस gcc क्या कहना है जब आप किसी अन्य int xbar अंदर डाल दिया है: अस्पष्टता

structinherit.c:4:27: error: duplicate member 'x' 
typedef struct { foo; int x; } bar; 
         ^

बचने के लिए आप के रूप में सिर्फ दोहराने struct, संभवतः #define घ कर सकते हैं

#include <stdio.h> 

typedef struct { int x; } foo; 
typedef struct { struct { int x; }; } bar; 

int main(void) 
{ 
    bar b; 
    b.x = 1; 
    printf("%d\n", b.x); 
} 

लेकिन किसी भी अनुरूप संकलक: किसी मैक्रो, लेकिन निश्चित रूप से, यह एक बिट बदसूरत लग रहा है इस कोड को स्वीकार करना चाहिए, इसलिए इस संस्करण से चिपके रहें।

< राय > यह एक दया है, मैं वाक्य रचना gcc से काफी बेहतर स्वीकार किए जाते हैं, लेकिन मानक के शब्द के रूप में यह स्पष्ट इस अनुमति देने के लिए नहीं है, केवल सुरक्षित शर्त ग्रहण करने के लिए है यह वर्जित है, तो clang यहां इसके लिए जिम्मेदार नहीं है ... </राय >

आप द्वारा x का उल्लेख करना चाहते हैं या तोb.xयाb.f.x, आप इस तरह एक अतिरिक्त गुमनाम संघ का उपयोग कर सकते हैं:

#include <stdio.h> 

typedef struct { int x; } foo; 
typedef struct { 
    union { struct { int x; }; foo f; }; 
} bar; 

int main(void) 
{ 
    bar b; 
    b.f.x = 2; 
    b.x = 1; 
    printf("%d\n", b.f.x); // <-- guaranteed to print 1 
} 

यह

§ की वजह से नहीं कारण अलियासिंग मुद्दों 6.5.2.3 जाएगा - 6

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

+0

शानदार प्रतिक्रिया। यह वास्तव में सवाल का जवाब देता है। बेनामी संरचनाएं जो मैं खोज रहा था, और यह बहुत संभव है कि मैं सी ++ 11 विशिष्ट कोड में देख रहा था। – Stewart

+1

@ स्टीवर्ट सी 11, ** ** ** सी ++ 11 के बारे में मेरी पूरी प्रतिक्रिया वार्ता नोट करें। मुझे नहीं पता कि यह सी ++ 11 पर भी लागू है या नहीं। –

2

सी में सी ++ में यह संभव नहीं है, हालांकि आप विरासत का उपयोग कर सकते हैं जो शायद आप सोच रहे थे।

0

सी ++ में, यह दो तरीकों से संभव है। पहला विरासत का उपयोग करना है। दूसरा barx (int &x) नामक संदर्भ सदस्य रखने के लिए है, और f.x को संदर्भित करने के लिए x प्रारंभ करने वाले निर्माता शामिल हैं।

सी में, यह संभव नहीं है।

3

सी (99 और आगे) में आप यूनियन सदस्यों के सामान्य प्रारंभिक उप-अनुक्रम तक पहुंच सकते हैं, भले ही वे पर लिखे गए अंतिम सदस्य न हों।

सी 11 में, आप अज्ञात संघ के सदस्य हो सकते हैं। तो:

typedef struct { int x; } foo; 
typedef struct { 
    union { 
    foo f; 
    int x; 
    }; 
} bar; 

  1. हाँ, संरचनाओं पर लागू होने वाला। लेकिन मानक के अनुसार:
    • एक संरचना सूचक, उपयुक्त रूप से परिवर्तित, पहले सदस्य को इंगित करता है।
    • एक यूनियन सूचक, उचित रूप से परिवर्तित, किसी भी संघ सदस्य को इंगित करता है।
    • तो स्मृति में उनका स्थान वही है।
5

सी में आप इस तरह के सदस्यों के सदस्यों तक नहीं पहुँच सकता।

आप फिर भी एक गुमनाम भीतरी struct की पहुँच सदस्य कर सकते हैं:

struct bar { 
    struct { 
     int x; 
    } 
}; 

... 
struct bar b; 
b.x = 1; 

C++ में आप विरासत का उपयोग करें:

struct foo { 
    int x; 
}; 

struct bar: public foo { 
}; 

... 
struct bar b; 
b.x = 1; 
2

C++ में, आप विरासत और सदस्य नाम संघर्ष उपयोग कर सकते हैं एक तरह से समाधान योग्य हैं :: के साथ और आधार वर्गों को सदस्यों के रूप में पेश करना।

struct foo { int x; }; 
struct bar : foo { }; 

struct foo1 { int x; }; 
struct bar1 : foo1 { char const* x; }; 

bar b; 
bar1 b1; 
int main() 
{ 
    return b.x + b1.foo1::x; 
} 

मानक सी में, यह है असंभव है, तथापि कई compilers (जीसीसी, बजना, tinycc) एक ऐसी ही बात एक विस्तार के रूप का समर्थन (आमतौर पर भी -fplan9-extensions साथ जीसीसी पर (-fms-extensions के साथ सुलभ जो -fms-extensions का सुपरसेट है)) , जो आपको करने की अनुमति देता है:

struct foo { int x; }; 
struct bar { struct foo; }; 
struct bar b = { 42 }; 
int main() 
{ 
    return b.x; 
} 

हालांकि, इसके साथ विवादित सदस्य नामों के लिए कोई समाधान नहीं है, AFAIK।

0

सी मानक की गारंटी देता है कि वहाँ एक struct के पहले सदस्य से पहले गद्दी नहीं है कि के बाद से, वहाँ bar में foo से पहले गद्दी नहीं है, और वहाँ foo में x से पहले गद्दी नहीं है। इसलिए, bar की शुरुआत में कच्ची मेमोरी एक्सेस bar::foo::x तक पहुंच जाएगी।

आप कुछ इस तरह कर सकता है:

#include <stdio.h> 
#include <stdlib.h> 

typedef struct _foo 
{ 
    int x; 
} foo; 

typedef struct _bar 
{ 
    foo f; 
} bar; 

int main() 
{ 
    bar b; 
    int val = 10; 

    // Setting the value: 
    memcpy(&b, &val, sizeof(int)); 
    printf("%d\n", b.f.x); 

    b.f.x = 100; 


    // Reading the value: 
    memcpy(&val, &b, sizeof(int)); 
    printf("%d\n", val); 
    return 0; 
} 

दूसरों के रूप में उल्लेख किया है, सी ++ विरासत के माध्यम से ऐसा करने का एक और अधिक सुरुचिपूर्ण तरीका प्रदान करता है।

7

सी: अत्यधिक unrecommended, लेकिन साध्य:

#include <stdio.h> 

#define BAR_STRUCT struct { int x; } 

typedef BAR_STRUCT bar; 

typedef struct { 
    union { 
     bar b; 
     BAR_STRUCT; 
    }; 
} foo; 

int main() { 
    foo f; 
    f.x = 989898; 
    printf("%d %d", f.b.x, f.x); 

    return 0; 
} 

बेनामी structs सी 11 से पहले मानकों में एक widly-प्रसार विस्तार कर रहे हैं।

सी ++: सी में के रूप में ही, आप यहाँ कर सकते लेकिन अनाम structs किसी भी सी ++ मानक का हिस्सा है, लेकिन एक विस्तार नहीं कर रहे हैं। बेहतर विरासत का उपयोग करें, या इस शॉर्टकट का बिल्कुल उपयोग न करें।

बेशक, #define x b.x जैसे कुछ का उपयोग न करें))।

+0

मुझे लगता है कि यह मैंने जो देखा है भूतकाल। मुझे संरचना संरेखण के संबंध में बहुत से मुद्दे याद हैं। बेशक '# परिभाषित 'सही है। – Stewart

+1

यदि आपके पास यूनियन में बिल्कुल वही 'संरचना' परिभाषा है, तो कोई संरेखण समस्या नहीं होगी। – Yuki

+0

@Yuki और इसलिए, इस तरह कुछ करने के लिए 'परिभाषित' वास्तव में एक * अच्छा विचार * है। –

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