C düşük seviyeli bir dildir, neredeyse taşınabilir bir montajcıdır, bu nedenle veri yapıları ve dil yapıları metale yakındır (veri yapılarının gizli bir maliyeti yoktur - dolgu ve hizalama ve donanım ve ABI tarafından uygulanan boyut kısıtlamaları hariç ). C gerçekten de doğal olarak dinamik yazmaya sahip değildir. Ama bunu gerekirse, bir evlat edinebiliriz kongre tüm değerler bir tür bilgilerle başlayan agrega olduğunu (örneğin bazı enum
...); Kullanım union
-s ve (dizi benzeri şeyleri) esnek dizi üyesi olarak struct
da dizinin boyutu ihtiva etmektedir.
(C dilinde programlama yapılırken, özellikle ön koşullar ve son koşullar ve değişmezler gibi yararlı kuralları tanımlamak, belgelemek ve takip etmek sizin sorumluluğunuzdadır; ayrıca C dinamik bellek tahsisi , bir free
miktar hafızalı malloc
bellek bölgesinin kiminle ilgili olması gerektiğini anlatan sözleşmeler gerektirir )
Bu nedenle, kutulu tamsayılar veya dizeler veya bir tür Şema benzeri sembol veya değer vektörleri olan değerleri temsil etmek için, kavramsal olarak, tür türünden başlayarak her zaman etiketli bir birlik (işaretçiler birliği olarak uygulanır) kullanırsınız. -, Örneğin:
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.
};
Bazı değerlerin dinamik türünü elde etmek için
enum value_kind_en value_type(value_t v) {
if (v.vptr != NULL) return *(v.vkind);
else return V_NONE;
}
İşte vektörlere "dinamik bir döküm":
struct vectvalue_st* dyncast_vector (value_t v) {
if (value_type(v) == V_VECTOR) return v->vvect;
else return NULL;
}
ve vektörlerin içinde "güvenli erişimci":
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;
}
Yukarıdaki kısa işlevlerin çoğunu static inline
bazı üstbilgi dosyalarında olduğu gibi tanımlarsınız .
BTW, Boehm'in çöp toplayıcısını kullanabiliyorsanız, daha üst düzey (ancak güvensiz) bir tarzda kolayca kodlayabilirsiniz ve birkaç Şema tercümanı bu şekilde yapılır. Değişken bir vektör oluşturucu
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};
}
ve üç değişkeniniz varsa
value_t v1 = somevalue(), v2 = otherval(), v3 = NULL_VALUE;
kullanarak onlardan bir vektör oluşturabilirsin make_vector(3,v1,v2,v3)
Boehm'in çöp toplayıcısını kullanmak istemiyorsanız (veya kendinizinkini tasarlayın) yıkıcıları tanımlamaya ve hafızanın kim, nasıl ve ne zaman olması gerektiğini belgelemeye çok dikkat etmelisiniz free
; bu örneğe bakın . Bu yüzden yukarıdaki malloc
yerine kullanabilirsiniz (ancak başarısızlığına karşı test edin), GC_MALLOC
ancak bazı yıkıcı işlevlerini dikkatlice tanımlamanız ve kullanmanız gerekir.void destroy_value(value_t)
C'nin gücü, yukarıdaki gibi kodu mümkün kılmak ve kendi kurallarınızı (yazılımınıza özel) tanımlamak için yeterince düşük seviyededir.