代码之家  ›  专栏  ›  技术社区  ›  Vardhman Patil

((void(*)(void))0)()是否为退出函数?[副本]

  •  0
  • Vardhman Patil  · 技术社区  · 7 年前

    我试图在Atmel AVR微控制器上编写自己的引导加载程序。我引用了github的一个代码库。我想感谢代码库 ZEVERO

    在初级阶段,我理解代码库。但在第224行我找到了一行 Reference to the code

    **if (pgm_read_word(0) != 0xFFFF) ((void(*)(void))0)();   //EXIT BOOTLOADER**
    

    我理解if条件部分,但当我试图理解真实陈述部分,即。

    **((void(*)(void))0)();**

    代码编写器对此进行了解释 //退出引导加载程序

    我的第一个问题是,这个复杂的声明是什么意思 **((void(*)(void))0)()**

    第二个问题是,它是否退出了微控制器中代码的执行。

    4 回复  |  直到 7 年前
        1
  •  11
  •   Mark Benningfield    7 年前

    正如@iBug所指出的, ((void(*)(void))0)(); 对空函数指针调用函数调用。

    实际上,这将程序控制转移到内存地址0。现在,在工作站上,这将是一个巨大的UB,很可能导致一个SEGFULT。

    然而,由于所讨论的代码是针对硬件引导加载程序的,它不是UB,它(显然)只是退出引导加载程序。

    在硬件层面,几乎 每件事 依赖于实现,几乎 没有什么 是便携式的。您不能期望针对特定硬件平台的C代码以任何方式代表公认的C模式和实践。

        2
  •  7
  •   lumato - Reinstate Monica    7 年前

    ((void(*)(void))0)(); 尝试调用空函数指针。AVR微控制器的用户程序(非引导加载程序)通常从地址0开始执行。AVR-GCC的ABI使用空函数指针的全0位表示,因此此调用将(除其他外)将执行转移到用户程序。本质上,它是 __asm__ __volatile__("jmp 0"); ,并假定用户程序的启动代码无论如何都会重新初始化堆栈指针。

    通过空函数指针调用是未定义的行为,因此不能保证此技巧适用于其他编译器、更高版本的GCC,甚至不同的优化设置。

    这个 if (pgm_read_word(0) != 0xFFFF) 调用前检查可能是为了确定是否存在用户程序:已擦除但未写入的程序内存字将读取为0xFFFF,而大多数程序以 JMP 跳过中断向量表其余部分和 JMP公司 指令从不为0xFFFF。

        3
  •  0
  •   tofro    7 年前

    如前所述,调用此函数只会导致跳转到地址0。

    由于此地址的代码通常不是由您自己的程序定义的,而是由特定的环境定义的,因此行为完全取决于此环境。

    您的问题标记为AVM/Atmel:在AVR上,跳转到地址0只会导致重新启动(与硬件重置行为几乎相同,但请注意,MCU将保持中断启用/禁用状态,而不是“真实”重置)。“更干净”的程序可能希望使用看门狗计时器进行“真正的”重置( wdt_reset() 等人)。

        4
  •  -1
  •   Antti Haapala -- Слава Україні    7 年前

    它将简单地调用地址0,就像它是一个返回的函数一样 void 不要争论。或更简单地说,地址是空指针的位模式。或者更简单地说,行为是未定义的,因此它可能会做任何意外的事情。