【问题标题】:Strange casting of function in c++ (void (**)())c++ 中函数的奇怪转换 (void (**)())
【发布时间】:2016-02-10 03:06:02
【问题描述】:

我在阅读code of the bitcoin trezor MCU 时发现了这个:

(*(void (**)())(FLASH_APP_START + 4))();

通过分解一些东西,我试图分析这条线的含义:

(   *(void (**)())(FLASH_APP_START + 4)    )      ();

我可以看到这是一个没有参数的函数调用,因为末尾有(),并且函数是任意的

*(void (**)())(FLASH_APP_START + 4)

指向。

我知道FLASH_APP_START + 4 会解析成什么东西,所以我只需要弄清楚这是什么:

*(void (**)())

它正在解析void (**)() 指向的任何内容。但是void (**)() 是什么?也许它看起来像是一个函数的转换。但我不确定。你能给我举个例子来说明这个呼召是什么吗?你为什么需要那个?

【问题讨论】:

    标签: c pointers casting trezor


    【解决方案1】:

    (void (**)())的含义是:转换成指向返回void的函数的指针。因此,当您取消引用它 (*(void(**)())) 时,它是指向返回 void 的函数的指针类型,您可以调用它。 (FLASH_APP_START+4) 是指向函数指针表的指针。如果FLASH_APP_START 的类型是char*,那么将调用列表中的第二个函数,假设是32 位指针。如果FLASH_APP_START的类型是void*,则调用表中的第5个函数。

    例如此代码将在具有 32 位指针的机器上调用 fun2

    #include <stdio.h>
    
    void fun1() { printf("fun1\n"); }
    void fun2() { printf("fun2\n"); }
    
    int main(void) {
      static void (*table[])() = { fun1, fun2 };
    
      int const FLASH_APP_START = (int)&table;
      (*(void (**)())(FLASH_APP_START + 4))();
    }
    

    如果您在解码 C 类型时需要帮助,cdecl.org 是您的朋友。

    【讨论】:

    • 你为什么使用 typedef?它让我感到困惑,有没有办法在没有 typedef 的情况下使用它?你怎么能重写'void'?允许吗?
    • @Gatonito 函数是一种抽象,可以用来打包一些代码。它不需要返回任何东西,它只是一种切碎的方式,让人类更容易消化。具有巨大功能的代码很难理解。编译器和机器都不关心函数是否返回任何东西。
    • @Gatonito 我没有“重写”void... typedef 使table 声明更易于阅读,仅此而已。如果愿意,您可以将 table 定义为 void (*table[])() = { ... }。任一定义的含义完全相同。
    • 你为什么把指针变成一个字符?我不应该将其转换为函数吗?
    • @Gatonito 不是char,而是char* - 有区别。 FLASH_APP_START is 已经被转换为一个函数,这就是你问题的重点。您在问题中链接到的代码看起来 FLASH_APP_START 是一个整数。它的类型是什么并不重要,它的工作原理都是一样的。你可以有int const FLASH_APP_START = (int)&amp;table;
    【解决方案2】:

    首先,void (**)() 是一个指向函数指针的指针,没有参数,返回类型为 void。

    其次,(void (**)())(FLASH_APP_START + 4) 表示将地址值FLASH_APP_START + 4 转换为第一步中的指针。 FLASH_APP_START 应该是一个固定值。可能是NAND flash的起始地址,在嵌入式系统中一直作为向量表使用。

    第三,*(void (**)())(FLASH_APP_START + 4) 解引用第二步得到的指针。我们现在得到了一个函数指针。

    最后(*(void (**)())(FLASH_APP_START + 4))()调用了我们第三步得到的函数。

    总结:地址FLASH_APP_START + 4处存储了一个函数入口地址。我们得到函数入口地址。将其转换为函数指针,然后调用它。

    【讨论】:

    • 参数列表 () 表示 C 中未指定的参数。(void) 表示没有参数。
    猜你喜欢
    • 2014-12-17
    • 2014-08-13
    • 1970-01-01
    • 2021-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-24
    相关资源
    最近更新 更多