了解获取内存位置的两段代码

时间:2019-06-21 12:43:08

标签: c memory-address bootloader

我有一个构建引导加载程序的任务,该加载程序虽然很成功,但引发了所有重要问题,说明其为何有效。通过它,我陷入了两行非常相似的代码中。

    //Get the application stack pointer (1st entry in the application vector table)
    appStack = (uint32_t) *((__IO uint32_t*) APPLICATION_ADDRESS);

    //Get the application entry address (2nd entry in the application entry table)
    appEntry = (pFunction) *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);

我已经定义了APPLICATION_ADDRESS。我已将pFunction定义为一个函数的指针。这是我的理解尝试:

(忽略__IO,因为这仅意味着volatile

(__IO uint32_t*) APPLICATION_ADDRESS)APPLICATION_ADDRESS强制转换为一个指针,该指针返回32位无符号整数。这意味着,如果我们转到地址APPLICATION_ADDRESS,将有一个存放uint32_t的存储位置的另一个地址。

*((__IO uint32_t *) APPLICATION_ADDRESS)中,我们使用解引用运算符来获取APPLICATION_ADDRESS所指向的值。 APPLICATION_ADDRESS指向另一个包含将返回值的地址。然后(uint32_t)将此值强制转换为uint32_t

按照我的理解,由于您已经说过括号中的变量为uint32_t,因此转换变得多余。

这与我对下一行的理解相矛盾。为什么我们最初没有将APP_ADDRESS + 4定义为pFunction

最后,我对方括号排列的差异感到困惑。为什么取消引用运算符不会像这样包围整个int_32(APPLICATION_ADDRESS +4)

*((__IO uint32_t*) (APPLICATION_ADDRESS + 4))

还是用括号括起来的过度杀伤力,只是不是必需的?

1 个答案:

答案 0 :(得分:3)

您有一些正确的假设和一些错误的假设。

您似乎在内存中的固定位置存储了2个值:

APPLICATION_ADDRESS + 0  +----------------------+
                         |     Stack            |
                    + 4  +----------------------+
                         |     pFunction        |
                    + 8  +----------------------+

现在让我们看看您的假设:

  

(__IO uint32_t*) APPLICATION_ADDRESS)APPLICATION_ADDRESS强制转换为   返回32位无符号整数的指针。

是的,正确。

  

这意味着,如果我们转到地址APPLICATION_ADDRESS,将会有另一个   存放uint32_t的内存位置的地址。

关闭但不正确。

在位置APPLICATION_ADDRESS处,您找不到另一个整数地址,但在其中找到了所述整数本身。

  

在*((____ uint32_t *)APPLICATION_ADDRESS)中,我们使用取消引用   运算符以获取APPLICATION_ADDRESS指向的值。

是的。 好吧,有点古怪,APPLICATION_ADDRESS并不指向任何地方。它只是一个普通数字,而不是指针。这就是为什么您需要对各种指针类型进行所有强制类型转换的原因。

  

APPLICATION_ADDRESS指向另一个包含值的地址   这将被退回。然后(uint32_t)将此值强制转换为   uint32_t

否,APPLICATION_ADDRESS 该整数的地址。

  

按照我的理解,将演员表冗余为   您已经说过,所保存的变量是uint32_t   括号。

正确。

  

这与我对下一行的理解相矛盾。为什么没有   我们将APP_ADDRESS + 4定义为方括号内的pFunction   最初?

从整数到指针的转换取决于实现。函数地址甚至更多。如果将内存内容定义为32位整数,则必须使用该类型读取它。然后,您可以根据需要进行任何转换。 这可能只会导致相同的值,也可能会有所不同。这取决于架构。

  

最后,我对方括号排列的差异感到困惑。   为什么取消引用运算符不包围整个int_32并   (APPLICATION_ADDRESS +4)像这样:

*((__IO uint32_t*) (APPLICATION_ADDRESS + 4))
     

还是用括号括起来的过度杀伤力,只是不是必需的?

不需要外部括号。 内括号很重要。没有括号,演员表将优先于加法。然后,您将不会在地址中添加4个字节,而是在此处添加4个内存对象的大小,即16个字节。