C एक निम्न-स्तरीय भाषा है, लगभग एक पोर्टेबल असेंबलर, इसलिए इसकी डेटा संरचनाएं और भाषा निर्माण धातु के करीब हैं (डेटा संरचनाओं में कोई छिपी हुई लागत नहीं है - हार्डवेयर और ABI द्वारा लगाए गए पैडिंग, संरेखण और आकार की बाधाओं को छोड़कर )। तो सी वास्तव में देशी रूप से गतिशील टाइपिंग नहीं करता है। लेकिन अगर आपको इसकी आवश्यकता है, तो आप एक कन्वेंशन अपना सकते हैं कि आपके सभी मूल्य कुछ प्रकार की जानकारी (जैसे कुछ ...) से शुरू होते हैं; उपयोग -s और (सरणी-जैसी चीजों के लिए) सरणी के आकार को रखने में लचीला सरणी सदस्य ।enum
union
struct
(जब 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 की ताकत निम्न-स्तर की पर्याप्त होनी चाहिए ताकि ऊपर की तरह कोड बना सकें और अपने स्वयं के सम्मेलनों को परिभाषित कर सकें (विशेष रूप से आपके सॉफ़्टवेयर के लिए)।