C是一种低级语言,几乎是一种便携式汇编程序,因此它的数据结构和语言构造接近金属(数据结构没有隐藏的成本-除了硬件和ABI施加的填充,对齐和大小限制之外)。因此,C确实本来就没有动态类型。但是,如果需要,可以采用一种约定,即所有值都是以某种类型信息(例如some ...)开头的集合。使用-s和(对数组状的东西)柔性阵列构件中还含有数组的大小。enum
union
struct
(在C语言中进行编程时,您有责任定义,记录和遵循有用的约定-特别是前置条件和后置条件以及不变量;C动态内存分配还需要明确约定哪些人应该使用free
某些堆积的malloc
内存区域)
因此,要表示装箱的整数,字符串或某种类似于Scheme的符号或值向量的值,则从概念上讲,您将使用带标记的并集(实现为指针的并集)-始终从类型kind开始-,例如:
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
在某些头文件中定义上面的大多数简短函数。
顺便说一句,如果您可以使用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的垃圾收集器(或设计自己的垃圾收集器),则在定义析构函数并记录谁,如何以及何时应使用free
-d 时应格外小心;看到这个例子。因此,您可以使用malloc
(但要对其失败进行测试)而不是GC_MALLOC
上面的方法,但是您需要仔细定义和使用一些析构函数void destroy_value(value_t)
C的强度应足够低,以使上面的代码成为可能,并定义您自己的约定(尤其是您的软件)。