C adalah bahasa tingkat rendah, hampir merupakan perakit portabel, sehingga struktur data dan konstruk bahasanya mendekati logam (struktur data tidak memiliki biaya tersembunyi - kecuali batasan bantalan, pelurusan dan ukuran yang dikenakan oleh perangkat keras dan ABI ). Jadi C memang tidak memiliki pengetikan dinamis secara asli. Tetapi jika Anda membutuhkannya, Anda dapat mengadopsi konvensi bahwa semua nilai Anda adalah agregat yang dimulai dengan beberapa jenis informasi (misalnya beberapa enum
...); use union
-s dan (untuk array-like things) anggota array fleksibel dalam struct
memuat juga ukuran array.
(saat memprogram dalam C, Anda bertanggung jawab untuk mendefinisikan, mendokumentasikan, dan mengikuti konvensi yang bermanfaat - terutama pra dan pasca kondisi dan invarian; juga alokasi memori dinamis C memerlukan konvensi penjelasan tentang siapa yang harus memiliki free
beberapa malloc
zona memori yang ditumpuk )
Jadi, untuk merepresentasikan nilai-nilai yang merupakan bilangan bulat kotak, atau string, atau semacam simbol seperti Skema , atau vektor nilai, Anda akan secara konseptual menggunakan gabungan tag (diimplementasikan sebagai gabungan pointer) -selalu dimulai dengan jenis ketik -, misalnya:
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.
};
Untuk mendapatkan tipe nilai yang dinamis
enum value_kind_en value_type(value_t v) {
if (v.vptr != NULL) return *(v.vkind);
else return V_NONE;
}
Berikut ini adalah "pemeran dinamis" untuk vektor:
struct vectvalue_st* dyncast_vector (value_t v) {
if (value_type(v) == V_VECTOR) return v->vvect;
else return NULL;
}
dan vektor "safe accessor" di dalam:
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;
}
Anda biasanya akan mendefinisikan sebagian besar fungsi pendek di atas seperti static inline
pada beberapa file header.
BTW, jika Anda dapat menggunakan pengumpul sampah Boehm, Anda kemudian dapat membuat kode dengan mudah dalam gaya tingkat tinggi (tetapi tidak aman), dan beberapa juru bahasa Skema melakukannya dengan cara itu. Konstruktor vektor variadik bisa jadi
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};
}
dan jika Anda memiliki tiga variabel
value_t v1 = somevalue(), v2 = otherval(), v3 = NULL_VALUE;
Anda dapat membangun vektor dari mereka menggunakan make_vector(3,v1,v2,v3)
Jika Anda tidak ingin menggunakan pengumpul sampah Boehm (atau mendesain sendiri milik Anda), Anda harus sangat berhati-hati dalam mendefinisikan destruktor dan mendokumentasikan siapa, bagaimana, dan kapan memori harus free
-d; lihat contoh ini . Jadi Anda bisa menggunakan malloc
(tapi kemudian menguji kegagalannya) alih-alih di GC_MALLOC
atas tetapi Anda perlu mendefinisikan dan menggunakan beberapa fungsi destruktor dengan hati-hativoid destroy_value(value_t)
Kekuatan C adalah level yang cukup rendah untuk membuat kode seperti di atas menjadi mungkin dan mendefinisikan konvensi Anda sendiri (khusus untuk perangkat lunak Anda).