C运行时类型检查

时间:2012-06-21 19:00:42

标签: c types

我有一个C库,用于存储包含许多字段的记录。从文本文件中读取模式,包括记录中每个字段的类型。

为了简化问题,想象一下

typedef enum my_type_enum
{
    INT32, //32-bit integer
    MYSTRUCT, //some struct I have, details irrelevant
    ...
} my_type_enum;

typedef struct my_var
{
    my_type_enum typetag;
    unsigned char* data;
} my_var;

my_var myrecord[numfields];

模式文件说明myrecord的每个字段是否应该包含int32_t或mystruct。我的库读取模式文件,myrecord中的每个my_var都设置标记并为数据分配适当的空间。

my_var是不透明的,客户端程序基本上用于简单数据

void set(my_var* record, size_t field, void * src)
{
    memcpy(record[field].data, src, datatypes[record[field].typetag].size);
}

int32_t x = 5; 
set(myrecord, 0, &x);

将值存储在记录中,并使用类似的get()来取消记录。

标记的my_var类型允许在my_var内部进行类型检查,但是如果模式说记录包含三个INT32,那么当你尝试设置时,当然没有什么可以检查src指向int32_t而不是mystruct ()数据到my_var。

显然,在将int32_t *或mystruct *转换为void *之前,需要在包装set()中进行检查。我看过使用typeof()技巧进行编译时检查。我觉得我想要的可能是不可能的,但你永远不会知道所有的技巧......

有什么办法比在客户端程序编译时提供读取模式的工具更好,并生成一个set_CHECKED()包装宏,如果有人试图将int32_t复制到my_var标记为保存mystruct,则会给编译器错误? GCC扩展很好。

1 个答案:

答案 0 :(得分:0)

实际上,'set'和'get'似乎是正确的放置位置 你的支票。如果访问具有错误类型的字段是致命的 错误,修复很简单:

void set(my_var* record, size_t field, void * src)
{
    if (record[field].typetag != (my_var)src->typetag) {
        fprintf(stderr, "Type mismatch!\n");
        exit(1);
    }
    memcpy(record[field].data, src, datatypes[record[field].typetag].size);
}

如果类型不匹配不是致命错误,则需要进行设置和 获取返回和错误代码并在呼叫站点正确处理。

请注意,在C中,类型信息在代码发布时消失了 编译。 'typetag'字段是您必须知道的唯一方式 一个字段的类型。

当然,如果您不需要能够更改架构 重新编译库,你可以尝试从它生成C代码。 这将允许您在编译时使用编译器的类型检查。

(另外:不是很重要,但my_var.data应该是一个空*,而不是一个char *。 这不会改变代码的正确性,但void *告诉了 类型未知的读者(和调试器)。)