0

我正在设计一个经典的虚拟机,它将在某种通用的、类型切换的值上运行——现在用一个标记的联合表示:

typedef struct val {
    val_type type;
    union {
        int            i;
        unsigned int   u;
        double         f;
        str *        str;
        vec *        vec;
        map *        map;
    };
} val;

我在网上找到了很多关于此的文献,并得出结论认为这是解决该问题的一种非常正统的方法。不过,我想知道是否可以通过以下方法提高性能:

typedef struct val_int {
    val_type type;
    int i;
};

typedef struct val_str {
    val_type type;
    char * buffer;
    size_t length;
    size_t capacity;
};

typedef struct val_vec {
    val_type type;
    val_type ** members; // <-- access member by cast
    size_t length;
    size_t capacity;
};

在这里,我的推理是,在访问原始类型的额外间接成本(以及需要执行单独的分配 - 可能通过池化帮助)与保存在集合中的内存(例如val_vec,减半)之间进行权衡它表示的当前胖指针的大小。我知道这里的简单答案将是“衡量它”,但我无法提出一个具有充分代表性的模型,该模型本身并不是一个完整的实现。

是否有第二种方法的名称,并且 - 假设这将被仔细管理(但假设它不会导致未定义的行为)是否存在我没​​有考虑到的广泛理解的风险?这里最好采用哪种方法?

顺便说一句,是否也可以类似地使用灵活的数组成员?

4

2 回答 2

1

在后一种情况下,您可能还定义

typedef union val {
    val_type           type;
    struct val_int     val_int;
    struct val_str     val_str;
    struct val_vec     val_vec;
} val;

现在你有了一个可以容纳任何值类型的联合类型。事实上,这是在匿名联合和结构存在之前的常用方法。当你有一个你知道永远是 val_int 的对象时,你可以通过分配一个 val_int 并将它的地址转换为一个val *.

于 2019-06-02T20:30:12.537 回答
0

我的推理是在访问原始类型的额外间接成本之间进行权衡

过早的优化很少值得您花费宝贵的编码时间。这里的任何变化充其量都是线性的。6.001 对 1/2 打其他。

在您选择的情况下,一种或另一种方式可能会更好,但是提供给编译器的信息越多,它就越有可能比您在此处进行更好的优化。

代码清晰,通常避免强制转换。

替代方案缺乏细节,并且考虑到通常的不正确假设可能会出现问题:void *或者val_type *是通用指针,指向 FP 的指针可以很好地转换为其他指针,强制转换的对齐方式对于其他类型就足够了,抗锯齿不是问题。

于 2019-06-02T19:16:51.943 回答