微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c – 使交换机重量级功能更具可重用性

假设我有这个代码

void ClassA::SomeFunction()
{
    switch(something)
    {
    case case1:
        doSomething();
        break;
    case case2:
        doSomethingElse();
        break;
       .
       . 
       .
}
...
void ClassB::SomeFunction()
{
    switch(something) // this 'something' is the same 'something' as in
    {                 // the above class
    case case1:
        doSomethingCompletelyUnrelatedToClassAFunction();
        break;
    case case2:
        doSomethingCompletelyUnrelatedToClassAOtherFunction();
        break;
       .
       . 
       .
}

在完全相同的情况下,两个类中的两个函数做了相当不同的事情(两个开关中的所有情况完全相同).
基本上我正在编写一个小型的Chip-8模拟器以获得乐趣,这两个类代表我的“cpu”和反汇编程序.

cpu应解码操作码并执行一些操作,而反汇编程序应根据操作码简单地格式化字符串.

我试图想办法避免复制/粘贴整个开关,只是改变每种情况下调用函数.

我提出的一个简单的解决方案是创建一个处理操作码的抽象类,并为交换机中的每个案例提供不同的方法. cpu和反汇编程序类都将扩展此类,并为每个方法实现自己的行为.但是,我希望有一个更优雅的解决方案.

谢谢.

编辑:

根据@Dogbert的评论,我添加了一大堆实际代码

wxString* DebugWindow::disassembleOpCode(uint16_t opCode)
{
wxString disLine;

uint8_t nibble1 = (opCode & 0xF000) >> 12;
uint8_t nibble2 = (opCode & 0x0F00) >> 8;
uint8_t nibble3 = (opCode & 0x00F0) >> 4;
uint8_t nibble4 = (opCode & 0x000F);

if (opCode == 0x00E0)
    disLine = "CLS";
else if (opCode == 0x00EE)
    disLine = "RET";
else
    switch (nibble1)
{
    case 0x1:
    {
                // JMP nnn
                disLine = wxString::Format("JMP %04x",nibble2 | nibble3 | nibble4);
                break;
    }
    case 0x2:
    {
                // CALL nnn
                disLine = wxString::Format("CALL %04x",nibble2 | nibble3 | nibble4);
                break;
    }
    case 0x3:
    {
                // SE V[x],nn  -- skip next instruction if V[x] == nn
                disLine = wxString::Format("SE V[%x],%02x",nibble2,nibble3 | nibble4);
                break;
    }

    ...
    ...
    ...

    case 0x8: // arithmetic operations between registers,see below
        {
                      switch (nibble4)
                      {
                      case 0x0:
                      {
                                  // LD V[x],V[y] -- sets value of register V[x] to value of register V[y]
                                  disLine = wxString::Format("ADD V[%x],V[%x]",nibble3);
                                  break;
                      }
                      case 0x1:
                      {
                                  // OR V[x],V[y] -- performs bitwise OR of values of registers V[x] and V[y],the result is stored in V[x]
                                  disLine = wxString::Format("OR V[%x],nibble3);
                                  break;
                      }

     ...
     ...

这是disassembleOpcode函数的一部分. cpu类中的Step函数实际上应该执行填充而不是格式化字符串,但它由相同的开关/案例组成.

解决方法

与dasblinkenlight建议的相同,我甚至会说“制表”指令集会大大提高设计的可读性.有点像:

struct opcode instructionset[] = {
{ 0x1000,"JMP %04x",&do_jump},...

然后,您的代码将访问每个指令的表,可能表格将按操作码排序以便快速查找:

struct opcode oP* = find(opCode,instructionset);
// for printing the instruction
disLine = wxString::Format(op->formatstring,opCode & op->format_mask);

你明白了……但关键是:你将拥有一个格式良好的已实现指令集表,我认为这将极大地简化维护/将来添加的指令.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐