在 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))()
我目前正在尝试实现 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 tovoid (*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))()