चर के आकार का सी "सच" कितना उपयोगी है?


9

एक चीज जो हमेशा सहज रूप से मुझे सी की एक सकारात्मक विशेषता के रूप में मारती है (ठीक है, वास्तव में इसके कार्यान्वयन जैसे gcc, clang, ...) तथ्य यह है कि यह रनवे पर अपने स्वयं के चर के बगल में किसी भी छिपी हुई जानकारी को संग्रहीत नहीं करता है। इससे मेरा मतलब है कि यदि आप उदाहरण के लिए "uint16_t" प्रकार का एक चर "x" चाहते हैं, तो आप यह सुनिश्चित कर सकते हैं कि "x" केवल 2 बाइट्स स्थान पर कब्जा कर लेगा (और इसके प्रकार जैसे किसी भी छिपी हुई जानकारी को नहीं ले जाएगा) ।)। इसी तरह, यदि आप 100 पूर्णांक चाहते हैं, तो आप यह सुनिश्चित कर सकते हैं कि यह 100 पूर्णांक जितना बड़ा हो।

हालांकि, जितना अधिक मैं इस सुविधा के लिए ठोस उपयोग के मामलों के साथ आने की कोशिश कर रहा हूं उतना ही मैं सोच रहा हूं कि क्या वास्तव में इसका कोई व्यावहारिक लाभ है। केवल एक चीज जो मैं अब तक कह सकता हूं, वह यह है कि स्पष्ट रूप से कम रैम की आवश्यकता है। सीमित वातावरण के लिए, जैसे एवीआर चिप्स आदि, यह निश्चित रूप से एक बहुत बड़ा प्लस है, लेकिन हर रोज डेस्कटॉप / सर्वर के मामलों के लिए, यह अप्रासंगिक लगता है। एक और संभावना है कि मैं सोच रहा हूँ कि यह हार्डवेयर तक पहुँचने के लिए सहायक / महत्वपूर्ण हो सकता है, या शायद मेमोरी क्षेत्रों को मैप करने के लिए (उदाहरण के लिए वीजीए आउटपुट और इसी तरह) ...?

मेरा प्रश्न: क्या ऐसे कोई ठोस डोमेन हैं जो या तो केवल इस सुविधा के बिना बहुत बोझिल हो सकते हैं या लागू किए जा सकते हैं?

PS कृपया मुझे बताएं कि क्या आपके पास इसके लिए बेहतर नाम है! ;)



@ मुझे लगता है कि मैं समझता हूं कि आपकी समस्या क्या है। यह इसलिए है क्योंकि वहाँ कई जवाब हो सकता है, है ना? ठीक है, मुझे लगता है कि यह सवाल स्टेक्सएक्सचेंज के काम करने के तरीके के अनुरूप नहीं हो सकता है, लेकिन मैं ईमानदारी से नहीं जानता कि कहां से पूछना है ...
थॉमस ओल्टमैन

1
@lxrec RTTI को वाइटटेबल में स्टोर किया जाता है, और ऑब्जेक्ट्स सिर्फ़ वाइबल को पॉइंटर स्टोर करते हैं। इसके अतिरिक्त, प्रकारों में केवल RTTI होता है यदि उनके पास पहले से ही एक व्यवहार्य है क्योंकि उनके पास एक virtualसदस्य फ़ंक्शन है। इसलिए RTTI कभी भी किसी भी ऑब्जेक्ट के आकार को नहीं बढ़ाता है, यह केवल बाइनरी को स्थिर बनाता है।

3
@ThomasOltmann वर्चुअल मेथड वाले प्रत्येक ऑब्जेक्ट को एक वाइबेटर पॉइंटर की आवश्यकता होती है। आपके पास इसके बिना कार्यक्षमता वर्चुअल तरीके नहीं हो सकते। इसके अलावा, आप स्पष्ट रूप से आभासी तरीकों (और इसलिए, एक व्यवहार्य) होने का विकल्प चुनते हैं।

1
@ThomasOltmann आप बहुत भ्रमित लगते हैं। यह एक ऑब्जेक्ट के लिए एक पॉइंटर नहीं है जो एक वाइबेटर पॉइंटर करता है, यह ऑब्जेक्ट ही है। यानी, T *हमेशा एक ही आकार का होता है और Tइसमें एक छिपी फ़ील्ड हो सकती है जो वाइबेट की ओर इशारा करती है। और कोई C ++ कंपाइलर कभी भी उन वस्तुओं में vtables नहीं डालता है जिनकी उन्हें आवश्यकता नहीं है।

जवाबों:


5

कई लाभ हैं, यह स्पष्ट करने के लिए कि यह सुनिश्चित करने के लिए संकलित समय पर है कि फ़ंक्शन पैरामीटर जैसी चीजें पास किए जा रहे मूल्यों से मेल खाती हैं।

लेकिन मुझे लगता है कि आप इस बारे में पूछ रहे हैं कि रनटाइम में क्या हो रहा है।

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

रनटाइम के दौरान चीजें आपकी सोच से थोड़ी अलग होती हैं।

उदाहरण के लिए, यह न मानें कि uint16_t घोषित करते समय केवल दो बाइट्स का उपयोग किया जाता है। प्रोसेसर और शब्द संरेखण के आधार पर यह स्टैक पर 16, 32 या 64 बिट्स पर कब्जा कर सकता है। आप पा सकते हैं कि शॉर्ट्स की आपकी सरणी आपकी अपेक्षा से बहुत अधिक मेमोरी का उपभोग करती है।

यह कुछ स्थितियों में समस्याग्रस्त हो सकता है जहां आपको विशिष्ट ऑफसेट पर डेटा को संदर्भित करने की आवश्यकता होती है। ऐसा तब होता है जब दो प्रणालियों के बीच संचार होता है जिसमें विभिन्न प्रोसेसर आर्किटेक्चर होते हैं, या तो वायरलेस लिंक के माध्यम से, या फाइलों के माध्यम से।

सी आपको बिट स्तर के साथ संरचना को निर्दिष्ट करने की अनुमति देता है:

struct myMessage {
  uint8_t   first_bit: 1;
  uint8_t   second_bit: 1;
  uint8_t   padding:6;
  uint16_t  somethingUseful;
}

यह संरचना तीन बाइट लंबी है, एक छोटी सी ऑफसेट पर शुरू करने के लिए परिभाषित है। आपको इसे परिभाषित करने के लिए भी पैक करने की आवश्यकता होगी। अन्यथा कंपाइलर सदस्यों को शब्द-संरेखित करेगा।

कंपाइलर इस डेटा को निकालने और एक रजिस्टर में कॉपी करने के लिए पर्दे के पीछे कोड उत्पन्न करेगा ताकि आप इसके साथ उपयोगी चीजें कर सकें।

अब आप देख सकते हैं कि हर बार जब मेरा प्रोग्राम MyMessage संरचना के किसी सदस्य तक पहुंचता है, तो यह पता चलेगा कि वास्तव में इसे कैसे निकालना है और इस पर काम करना है।

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

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


2
"आप पा सकते हैं कि आपके शॉर्ट्स की सरणी आपकी अपेक्षा से बहुत अधिक मेमोरी का उपभोग करती है।" यह C में गलत है: Arrays को उनके तत्वों को एक अंतर-मुक्त फैशन में शामिल करने की गारंटी है। हां, एक एकल के रूप में, सरणी को ठीक से संरेखित करने की आवश्यकता है short। लेकिन यह सरणी की शुरुआत के लिए एक बार की आवश्यकता है, बाकी को लगातार होने के आधार पर स्वचालित रूप से सही ढंग से संरेखित किया जाता है।
सेंटास्टर -

इसके अलावा, गद्दी के लिए वाक्य रचना गलत है, यह uint8_t padding: 6;पहले दो बिट्स की तरह होना चाहिए । या, अधिक स्पष्ट रूप से, सिर्फ टिप्पणी //6 bits of padding inserted by the compiler। संरचना, जैसा कि आपने लिखा है, कम से कम नौ बाइट का आकार है, तीन नहीं।
विस्फ़ोटक -

9

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


5

C एक निम्न-स्तरीय भाषा है, लगभग एक पोर्टेबल असेंबलर, इसलिए इसकी डेटा संरचनाएं और भाषा निर्माण धातु के करीब हैं (डेटा संरचनाओं में कोई छिपी हुई लागत नहीं है - हार्डवेयर और ABI द्वारा लगाए गए पैडिंग, संरेखण और आकार की बाधाओं को छोड़कर )। तो सी वास्तव में देशी रूप से गतिशील टाइपिंग नहीं करता है। लेकिन अगर आपको इसकी आवश्यकता है, तो आप एक कन्वेंशन अपना सकते हैं कि आपके सभी मूल्य कुछ प्रकार की जानकारी (जैसे कुछ ...) से शुरू होते हैं; उपयोग -s और (सरणी-जैसी चीजों के लिए) सरणी के आकार को रखने में लचीला सरणी सदस्यenumunionstruct

(जब C में प्रोग्रामिंग की जाती है, तो यह आपकी जिम्मेदारी है कि आप उपयोगी सम्मेलनों को परिभाषित करें, उनका पालन ​​करें - विशेष रूप से पूर्व और बाद की स्थितियों और अपरिवर्तनीयों का; सी गतिशील डायनेमिक आवंटन के बारे में भी ऐसे सम्मेलनों की खोज करने की आवश्यकता होती है, जिन्हें freeकुछ कम से कम mallocस्मृति क्षेत्र में होना चाहिए )

तो, उन मूल्यों का प्रतिनिधित्व करने के लिए जो बॉक्सर पूर्णांक, या तार, या किसी प्रकार के स्कीम -समान प्रतीक , या मानों के वैक्टर हैं, आप वैचारिक रूप से एक टैग किए गए संघ (बिंदुओं के एक संघ के रूप में लागू) का उपयोग करेंगे- प्रकार से शुरू होने वाले रास्ते -, उदा:

enum value_kind_en {V_NONE, V_INT, V_STRING, V_SYMBOL, V_VECTOR};
union value_en { // this union takes a word in memory
   const void* vptr; // generic pointer, e.g. to free it
   enum value_kind_en* vkind; // the value of *vkind decides which member to use
   struct intvalue_st* vint;
   struct strvalue_st* vstr;
   struct symbvalue_st* vsymb;
   struct vectvalue_st* vvect;
};
typedef union value_en value_t;
#define NULL_VALUE  ((value_t){NULL})
struct intvalue_st {
  enum value_kind_en kind; // always V_INT for intvalue_st
  int num;
};
struct strvalue_st {
  enum value_kind_en kind; // always V_STRING for strvalue_st
  const char*str;
};
struct symbvalue_st {
  enum value_kind_en kind; // V_SYMBOL
  struct strvalue_st* symbname;
  value_t symbvalue;
};
struct vectvalue_st {
  enum value_kind_en kind; // V_VECTOR;
  unsigned veclength;
  value_t veccomp[]; // flexible array of veclength components.
};

कुछ मूल्य के गतिशील प्रकार प्राप्त करने के लिए

enum value_kind_en value_type(value_t v) {
  if (v.vptr != NULL) return *(v.vkind);
  else return V_NONE;
}

यहाँ वैक्टरों को "डायनेमिक कास्ट" दिया गया है:

struct vectvalue_st* dyncast_vector (value_t v) {
   if (value_type(v) == V_VECTOR) return v->vvect;
   else return NULL;
}

और वैक्टर के अंदर एक "सुरक्षित एक्सेसर":

value_t vector_nth(value_t v, unsigned rk) {
   struct vectvalue_st* vecp = dyncast_vector(v);
   if (vecp && rk < vecp->veclength) return vecp->veccomp[rk];
   else return NULL_VALUE;
}

आप आमतौर पर static inlineकुछ हेडर फ़ाइल की तरह ऊपर दिए गए अधिकांश छोटे कार्यों को परिभाषित करेंगे ।

BTW, यदि आप बोहेम के कचरा कलेक्टर का उपयोग कर सकते हैं तो आप कुछ उच्च-स्तरीय (लेकिन असुरक्षित) शैली में आसानी से कोड करने में सक्षम हैं, और कई योजना दुभाषियों को इस तरह से किया जाता है। एक वैरिएड वेक्टर कंस्ट्रक्टर हो सकता है

value_t make_vector(unsigned size, ... /*value_t arguments*/) {
   struct vectvalue_st* vec = GC_MALLOC(sizeof(*vec)+size*sizeof(value));
   vec->kind = V_VECTOR;
   va_args args;
   va_start (args, size);
   for (unsigned ix=0; ix<size; ix++) 
     vec->veccomp[ix] = va_arg(args,value_t);
   va_end (args);
   return (value_t){vec};
}

और अगर आपके पास तीन चर हैं

value_t v1 = somevalue(), v2 = otherval(), v3 = NULL_VALUE;

आप उन से एक वेक्टर का निर्माण कर सकते हैं make_vector(3,v1,v2,v3)

यदि आप बोहेम के कचरा संग्राहक का उपयोग नहीं करना चाहते हैं (या अपनी खुद की डिज़ाइन करें) आपको विनाशकों को परिभाषित करने और यह याद रखने में बहुत सावधानी बरतनी चाहिए कि कौन, कैसे और कब स्मृति free-d होना चाहिए ; इस उदाहरण को देखें । इसलिए आप ऊपर के mallocबजाय (लेकिन फिर इसकी विफलता के खिलाफ परीक्षण) का उपयोग कर सकते हैं GC_MALLOCलेकिन आपको सावधानीपूर्वक परिभाषित करने और कुछ विनाशकारी फ़ंक्शन का उपयोग करने की आवश्यकता हैvoid destroy_value(value_t)

C की ताकत निम्न-स्तर की पर्याप्त होनी चाहिए ताकि ऊपर की तरह कोड बना सकें और अपने स्वयं के सम्मेलनों को परिभाषित कर सकें (विशेष रूप से आपके सॉफ़्टवेयर के लिए)।


मुझे लगता है कि आपने मेरे सवाल को गलत समझा। मैं सी में डायनेमिक टाइपिंग नहीं करना चाहता हूं। मैं उत्सुक था कि क्या सी की यह विशिष्ट संपत्ति किसी व्यावहारिक उपयोग की है।
थॉमस ओल्टमन

लेकिन सी की सटीक संपत्ति आप किसका उल्लेख कर रहे हैं? सी डेटा संरचनाएं धातु के करीब हैं, इसलिए कोई छिपी हुई लागत (संरेखण और आकार की बाधाओं को छोड़कर) नहीं है
बेसिल स्टायरनेविच

बिल्कुल सही: /
थॉमस ओल्टमैन

C का आविष्कार एक निम्न-स्तरीय भाषा के रूप में किया गया था, लेकिन जब अनुकूलन को gcc की तरह संकलक में बदल दिया जाता है, तो ऐसी भाषा का उपयोग किया जाता है, जो निम्न-स्तरीय सिंटैक्स का उपयोग करती है, लेकिन विश्वसनीय रूप से प्लेटफ़ॉर्म-प्रदत्त व्यवहारिक गारंटी के लिए निम्न-स्तरीय पहुँच प्रदान नहीं करती है।
मॉलॉक और मेम्के
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.