前段时间我创建了一个简单的模拟计算机。它有外围设备,可以渲染为OpenGL纹理的屏幕缓冲区,以及其他一些简洁的功能。它运作良好,效果很好,总的来说我很满意。
除此之外,我作弊。
底层数据类型是整数,浮点和指令类型的并集(拆分为位字段)。
对于任何正确的(模拟的)程序,union总是安全使用,只读取写入的最后一个union成员。但是,一个格式错误的程序(例如从模拟硬盘驱动器加载)可能无法访问成员的可能性可能使我暴露于与工会滥用相关的常见问题:
考虑的解决方案:
我认为这是许多SO用户曾经尝试过的那种项目,所以特别欢迎特定问题的体验。
答案 0 :(得分:3)
如果您的编译器支持它,您可以使用C ++ 17 std::variant
(基于boost::variant
)。
编辑:为了最大限度地节省空间,选择加入类型安全,你可以做点什么
union Word { int32_t i; float f; Instruction inst; };
namespace MemAccess
{
static std::bitset<MEM_SIZE> int32_whitelist,
float_whitelist,
inst_whitelist;
static std::array<Word, MEM_SIZE> memory;
// set or reinterpret as int32
int32_t &
int32_at(const size_t at)
{
int32_whitelist[at] = 1;
float_whitelist[at] = inst_whitelist[at] = 0;
return memory[at].i;
}
// interpret as int32 only if whitelisted
int32_t &
int32_checked(const size_t at)
{
if (int32_whitelist[at])
{
return memory[at].i;
}
else
{
throw;
}
}
// equivalent functions for floats and instructions
}
编辑2:发生在我身上也可以用一个bitset完成。
static std::array<Word, MEM_SIZE> memory;
static std::bitset<MEM_SIZE * 2> whitelist;
float &
float_at(const size_t at)
{ // None = 00, Inst = 10, Int32 = 11
whitelist[at * 2] = 0;
whitelist[at * 2 + 1] = 1;
return memory[at].f;
}
float &
float_checked(const size_t at)
{
if (!whitelist[at * 2] && whitelist[at * 2 + 1])
{
return memory[at].f;
}
throw;
}