C++ 试图将地址转换为 void* 并分配给函数指针(以便我的引导加载程序可以跳转到实际的应用程序)
C++ trying to cast address to void* and assign to function pointer (so that my bootloader can jump to actual app)
我正在为 STM32 编写引导加载程序,我需要从引导加载程序跳转到真正的应用程序。
在 C 中这是可行的,因为我可以将地址转换为空指针并将其分配给函数指针,然后按如下方式调用函数指针:
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
void (*app_reset_handler)(void) = (void *)reset_handler_add;
SCB->VTOR = address;
uint32_t msp_value = *((volatile uint32_t *)address);
__set_MSP(msp_value);
app_reset_handler();
}
如果我在 C++ 中使用相同的实现,gnu 编译器将在转换为 void 指针时给出错误。
include/bootloader.hpp:58:39: error: invalid conversion from 'void*'
to 'void (*)()' [-fpermissive]
谷歌搜索后我发现 this SO page,我尝试并在我的 class 中实现了以下实现:
void JumpToApp()
{
// Quick test if C style cast does work
//jump_to_firmware(_appStartAddress);
uint32_t mspAdress = *((volatile uint32_t *)_appStartAddress);
uint32_t resetHandlerAddress = *((volatile uint32_t *)(_appStartAddress + sizeof(uint32_t)));
//
typedef void (*functionPointer)();
functionPointer resetHandler = 0;
reinterpret_cast<void*&>(resetHandler) = (void*)resetHandlerAddress;
SCB->VTOR = _appStartAddress;
__set_MSP(mspAdress);
resetHandler();
}
在 C++ 实现中:
functionPointer resetHandler
被分配 0x8035065
SCB->VTOR
被分配 0x08020000
mspAddress
分配了 `0x20020000
- 然后调用函数指针
resetHandler
在 C 实现中:
app_reset_handler
被分配 0x8035065
SCB->VTOR
被分配 0x08020000
mspAddress
分配了 `0x20020000
- 然后调用函数指针
app_reset_handler
C 实现有效,它跳转到我的应用程序,应用程序运行没有问题。
C++ 实现无处可去。它hangs/crashes放在下面(对我来说毫无意义)地址:
我试图将源文件的数量保持在最低限度,所以我想将逻辑保留在单个 class 定义中。
我的问题:
- 我是否误解了链接的 SO 页面,有人可以看到我在 C++ 实现中哪里出错了吗?
- 在 C++ 中是否有 better/easier 将地址转换为函数指针的方法?
- 或者是否存在无法在 C++ 中完成的技术原因?
PS:在两种情况下,引导程序代码是相同的。我在测试这两种实现时所做的唯一区别是注释掉 Bootloader::JumpToApp
中的代码并改为调用 C 函数 jump_to_firmware(uint32_t)
。
PPS:所有外设都正确去初始化。同样,它工作正常,只有当我使用这个 C++ 实现时才会出现问题。
相同的代码将在 C 和 C++ 中编译。您必须简单地转换为正确的转换(在 C++ 中,您不能将 void *
分配给非 void *
指针。它比在 C 中严格得多。
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
void (*app_reset_handler)(void) = (void (*)(void))reset_handler_add;
/* ... */
}
如果您不喜欢那些奇怪的转换,您可以对函数进行类型定义。
typedef void handler(void);
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
handler *app_reset_handler = (handler *)reset_handler_add;
/* ... */
}
我正在为 STM32 编写引导加载程序,我需要从引导加载程序跳转到真正的应用程序。
在 C 中这是可行的,因为我可以将地址转换为空指针并将其分配给函数指针,然后按如下方式调用函数指针:
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
void (*app_reset_handler)(void) = (void *)reset_handler_add;
SCB->VTOR = address;
uint32_t msp_value = *((volatile uint32_t *)address);
__set_MSP(msp_value);
app_reset_handler();
}
如果我在 C++ 中使用相同的实现,gnu 编译器将在转换为 void 指针时给出错误。
include/bootloader.hpp:58:39: error: invalid conversion from 'void*' to 'void (*)()' [-fpermissive]
谷歌搜索后我发现 this SO page,我尝试并在我的 class 中实现了以下实现:
void JumpToApp()
{
// Quick test if C style cast does work
//jump_to_firmware(_appStartAddress);
uint32_t mspAdress = *((volatile uint32_t *)_appStartAddress);
uint32_t resetHandlerAddress = *((volatile uint32_t *)(_appStartAddress + sizeof(uint32_t)));
//
typedef void (*functionPointer)();
functionPointer resetHandler = 0;
reinterpret_cast<void*&>(resetHandler) = (void*)resetHandlerAddress;
SCB->VTOR = _appStartAddress;
__set_MSP(mspAdress);
resetHandler();
}
在 C++ 实现中:
functionPointer resetHandler
被分配0x8035065
SCB->VTOR
被分配0x08020000
mspAddress
分配了 `0x20020000- 然后调用函数指针
resetHandler
在 C 实现中:
app_reset_handler
被分配0x8035065
SCB->VTOR
被分配0x08020000
mspAddress
分配了 `0x20020000- 然后调用函数指针
app_reset_handler
C 实现有效,它跳转到我的应用程序,应用程序运行没有问题。
C++ 实现无处可去。它hangs/crashes放在下面(对我来说毫无意义)地址:
我试图将源文件的数量保持在最低限度,所以我想将逻辑保留在单个 class 定义中。
我的问题:
- 我是否误解了链接的 SO 页面,有人可以看到我在 C++ 实现中哪里出错了吗?
- 在 C++ 中是否有 better/easier 将地址转换为函数指针的方法?
- 或者是否存在无法在 C++ 中完成的技术原因?
PS:在两种情况下,引导程序代码是相同的。我在测试这两种实现时所做的唯一区别是注释掉 Bootloader::JumpToApp
中的代码并改为调用 C 函数 jump_to_firmware(uint32_t)
。
PPS:所有外设都正确去初始化。同样,它工作正常,只有当我使用这个 C++ 实现时才会出现问题。
相同的代码将在 C 和 C++ 中编译。您必须简单地转换为正确的转换(在 C++ 中,您不能将 void *
分配给非 void *
指针。它比在 C 中严格得多。
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
void (*app_reset_handler)(void) = (void (*)(void))reset_handler_add;
/* ... */
}
如果您不喜欢那些奇怪的转换,您可以对函数进行类型定义。
typedef void handler(void);
void jump_to_firmware(uint32_t address)
{
uint32_t reset_handler_add = *((volatile uint32_t *)(address + 4));
handler *app_reset_handler = (handler *)reset_handler_add;
/* ... */
}