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++ 实现中:

在 C 实现中:

C 实现有效,它跳转到我的应用程序,应用程序运行没有问题。

C++ 实现无处可去。它hangs/crashes放在下面(对我来说毫无意义)地址:

我试图将源文件的数量保持在最低限度,所以我想将逻辑保留在单个 class 定义中。

我的问题:

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;
    /* ... */ 
}