在 vector 中调用函数指针不会做任何事情

Calling function pointer inside vector doesn't do anything

我目前正在尝试实现 CHIP-8 仿真器。在这些仿真器中,您可以读取盒式磁带的内容,它会为您提供“操作码”,即与函数对应的值。我不想写一个巨大的 switch case 语句来处理这些操作码(在 CHIP-8 模拟器的上下文中,这没关系,因为没有太多的操作码,但在​​ Gameboy 模拟器的上下文中,例如,它可以产生一些巨大的 switch case 语句)。

我的做法如下:

我有一个包含操作码范围、函数名称和函数指针的结构 (void* func)。

struct instruction {
    std::pair<uint16_t, uint16_t> range;
    std::string name;
    void* func;

    instruction(std::pair<uint16_t, uint16_t> range, std::string name, void* func) {
        this->range = range;
        this->name = name;
        this->func = func;
    }
};

我的 class 看起来像这样(请不要打我,我现在已经把所有东西都放在 public 了,但是当一切正常时,东西会变成私有的):

class Chip8 {
    public:
        Chip8();
        virtual ~Chip8();

        void set_opcodes(void);

        bool load_cartridge(std::string path);
        void output_cartridge_contents(void);
        bool verifiy_instructions(void);

        void JUMP(void);

        // 0     -> 0x1FF: interpreter (unused since the emulator is running outside of the memory)
        // 0x200 -> 0xE9F: cartridge data
        // 0xEA0 -> 0xEFF: call stack, internal use, and other variables
        // 0xF00 -> 0xFFF: display refresh
        std::vector<uint8_t> memory;
        std::vector<uint8_t> registers;

        // Index register
        uint16_t I;
        // Program counter
        uint16_t pc;

        std::vector<uint8_t> stack;
        // Stack pointer
        uint8_t sp;

        std::vector<instruction> instr;

        // Timers
        uint8_t delay_timer;
        uint8_t sound_timer;

        uint16_t opcode;

        // Screen
        bool gfx[64 * 32];

};

我们举个例子,JUMP

void Chip8::JUMP(void) {
    this->pc = (this->opcode & 0x0FFF);
}

然后我将填充一个包含所有已实现操作码的向量,

this->instr.push_back(instruction(std::pair<uint16_t, uint16_t>(0x1000,0x1FFF), std::string("JUMP"), (void*)&Chip8::JUMP))

读取当前操作码,然后与实现的函数范围进行比较(例如,如果操作码是0x1225,将调用JUMP函数)。找到正确的函数后,将调用以下代码(i 是上面显示的 instr 向量中正确 instruction 的索引):

this->instr[i].func;

但是当我这样做时,没有任何反应(即 pc 的值没有改变,std::cout 在控制台上什么也没有产生,等等)。我尝试了多种方法(将 func 类型更改为 void (*func)(void),尝试调用 this->instr[i].func();),但到目前为止还没有成功。我想我在这里遗漏了一些东西。有人有一些指示吗?

谢谢

因为Chip8::JUMP是一个非静态class成员函数,你需要一个class的对象来调用这个函数。这是因为非静态成员函数有一个 class 类型的隐式第一个参数,用于在函数内部启用 this 的使用。

您可以通过使用 std::function 并使用 lambda 或 std::bind 将函数绑定到对象来解决此问题。看起来像

struct instruction {
    std::pair<uint16_t, uint16_t> range;
    std::string name;
    std::function<void(void)> func;

    template<typename Func>
    instruction(std::pair<uint16_t, uint16_t> range, std::string name, Func func) : range(range), name(name), func(func) {}
};

//...

this->instr.push_back(instruction(std::pair<uint16_t, uint16_t>(0x1000,0x1FFF), std::string("JUMP"), [this]{ this->JUMP(); }))

// and call it like

this->instr[i].func();

pointer to the function (void* func).

void * 不是指向函数的指针。它是一个指向对象的指针。

(void*)&Chip8::JUMP

这是一个糟糕的演员阵容。成员函数指针不能有意义地转换为 void*。通过转换后的指针进行间接操作会有未定义的行为(即使转换回正确的类型)。

this->instr[i].func;

But when I do this, nothing happens

this->instr[i].func; 不是函数调用表达式。这是一个 id 表达式。 Id 表达式没有副作用。

所有函数调用表达式都有包含(可能为空)参数列表的括号。

I've tried multiple approaches (changing func type to void (*func)(void)

void (*func)(void) 一个函数指针。但它不是成员函数指针。您不能将 &Chip8::JUMP 转换为函数指针。

trying to call this->instr[i].func();

这是一个函数调用表达式,所以你越来越接近了。这将是函数指针的正确语法,但您已尝试使用非静态成员函数,因此函数指针不适合您。


你可以把instruction做成一个模板,然后使用成员函数指针:

template<class T>
struct instruction {
    void (T::*func)(); // a pointer to member function
    // ...
};

// insert
instr.emplace_back(/* other member initializers */, &JUMP);

// call
(this->*(instr[i].func))()