C เป็นภาษาระดับต่ำเกือบจะเป็นชุดประกอบแบบพกพาดังนั้นโครงสร้างข้อมูลและโครงสร้างภาษาจึงใกล้เคียงกับโลหะ (โครงสร้างข้อมูลไม่มีค่าใช้จ่ายแอบแฝงยกเว้นการเว้นระยะห่างการจัดตำแหน่งและขนาดที่กำหนดโดยฮาร์ดแวร์และABI ) ดังนั้น C แน่นอนไม่มีการพิมพ์แบบไดนามิก แต่ถ้าคุณต้องการคุณสามารถยอมรับข้อตกลงที่ว่าค่าทั้งหมดของคุณเป็นผลรวมเริ่มต้นด้วยข้อมูลประเภท (เช่นบางenum
... ); ใช้union
-s และ (สำหรับอาร์เรย์เหมือนสิ่ง) สมาชิกของอาร์เรย์ที่มีความยืดหยุ่นในการstruct
ที่มียังมีขนาดของอาร์เรย์
(เมื่อการเขียนโปรแกรมใน C มันเป็นความรับผิดชอบของคุณเพื่อกำหนดเอกสารและตามธรรมเนียมปฏิบัติที่มีประโยชน์ - เงื่อนไขสะดุดตาก่อนและหลังและค่าคงที่; ยังจัดสรร C หน่วยความจำแบบไดนามิกต้อง expliciting การประชุมเกี่ยวกับผู้ที่ควรfree
heap- บางmalloc
โซนหน่วยความจำ ated)
ดังนั้นเพื่อเป็นตัวแทนของค่าที่เป็นจำนวนเต็มชนิดบรรจุกล่องหรือสตริงหรือสัญลักษณ์บางอย่างของScheme - like หรือเวกเตอร์ของค่าคุณจะใช้แนวคิดที่ติดแท็กสหภาพ (ดำเนินการเป็นสหภาพของพอยน์เตอร์) - ทางเริ่มต้นโดยชนิด -, เช่น:
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;
}
และ "safe accessor" ภายในเวกเตอร์:
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 ถ้าคุณสามารถใช้ถังเก็บขยะของ Boehmคุณจะสามารถเขียนโค้ดได้ค่อนข้างง่ายในสไตล์ระดับสูง (แต่ไม่ปลอดภัย) และล่าม Scheme หลายคนก็ทำเช่นนั้น คอนสตรัคเตอร์เวกเตอร์แบบผันแปรอาจเป็น
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)
หากคุณไม่ต้องการใช้ถังเก็บขยะของ Boehm (หรือออกแบบเอง) คุณควรระวังอย่างมากเกี่ยวกับการกำหนด destructors และจัดทำเอกสารใครอย่างไรและเมื่อไรควรจะมีหน่วยความจำfree
-d; ดูนี้ตัวอย่างเช่น ดังนั้นคุณสามารถใช้malloc
(แต่ทดสอบกับความล้มเหลว) แทนGC_MALLOC
ข้างบน แต่คุณต้องกำหนดและใช้ฟังก์ชัน destructor อย่างระมัดระวังvoid destroy_value(value_t)
จุดแข็งของ C คืออยู่ในระดับต่ำพอที่จะทำให้โค้ดดังกล่าวเป็นไปได้และกำหนดอนุสัญญาของคุณเอง (โดยเฉพาะกับซอฟต์แวร์ของคุณ)