在向量内调用函数指针不会做任何事情

问题描述 投票:2回答:2

我目前正在尝试实现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;
    }
};

我的班级看起来像这样(请点击我,我现在把所有的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是上面显示的instruction向量中正确的instr的索引):

this->instr[i].func;

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

谢谢

c++ function-pointers
2个回答
5
投票

由于Chip8::JUMP是一个非静态类成员函数,因此您需要该类的对象来调用该函数。这是因为非静态成员函数具有类类型的隐式第一个参数,用于在函数内部使用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();

1
投票

指向函数的指针(void* func)。

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

(void*)&Chip8::JUMP

这是一个糟糕的演员。成员函数指针无法有意义地转换为void*。通过转换后的指针指向未定义的行为(即使转换回正确的类型)。

this->instr[i].func;

但是当我这样做时,没有任何反应

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

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

我尝试了多种方法(将func类型更改为void (*func)(void)

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

试图打电话给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))() 
© www.soinside.com 2019 - 2024. All rights reserved.