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

我的任务是构建一个成功的引导加载程序,但却引出了一个非常重要的问题:为什么它能工作。通过它,我被两行非常相似的代码难住了。

    //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)强制转换为返回32位无符号整数的指针。这意味着,如果我们转到地址APPLICATION_ADDRESS,将有另一个存储位置的地址来保存APPLICATION_ADDRESS
uint32_t中,我们使用解引用运算符来获得*((__IO uint32_t *) APPLICATION_ADDRESS)所指向的值APPLICATION_ADDRESS指向另一个地址,该地址包含将返回的值。然后APPLICATION_ADDRESS将该值转换为(uint32_t)
按照我的理解,使转换成为多余的,正如你已经说过的,变量在括号内uint32_t
这就违背了我对下一行的理解。为什么我们不把uint32_t定义为括号内的APP_ADDRESS + 4
最后,我对括号中的不同安排感到困惑。为什么解引用运算符不围绕整个pFunctionint_32这样:
(APPLICATION_ADDRESS +4)
或者这是用括号过度杀戮,只是不需要?


最佳答案:

你有一些正确的假设和一些错误的假设。
您的内存中似乎有两个值存储在固定位置:

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

现在让我们看看你的假设:
(__IO uint32_t*) APPLICATION_ADDRESS)
返回32位无符号整数的指针。
是的,没错。
这意味着如果我们转到地址APPLICATION_ADDRESS将有另一个
存放uint32的内存位置的地址。
接近但不是真的。
APPLICATION_ADDRESS位置找不到整数的另一个地址,但在那里可以找到所述整数本身。
在*(uint32)应用程序地址中,我们使用解引用
运算符以获取APPLICATION_ADDRESS所指向的值。
对。
好吧,有点迂腐,APPLICATION_ADDRESS没有任何意义。它只是一个普通的数字,不是指针。这就是为什么需要对各种指针类型执行所有强制转换的原因。
APPLICATION_ADDRESS指向另一个包含值的地址
将被归还。APPLICATION_ADDRESS然后将该值转换为
(uint32_t)
不,uint32_t是那个整数的地址。
按照我的理解,这个角色是多余的
你已经说过变量在
括号。
对的。
这就违背了我对下一行的理解。为什么没有
我们将APPLICATION_ADDRESS定义为括号内的一个函数
最初?
从整数到指针的转换依赖于实现。对于函数地址更是如此。如果内存内容定义为32位整数,则必须使用该类型读取它。如果需要,您可以进行任何转换。
这可能只会产生相同的值,也可能不同。这取决于建筑。
最后,我对括号中的不同安排感到困惑。
为什么解引用运算符不包围整个APP_ADDRESS + 4
像这样:
*((__IO uint32_t*) (APPLICATION_ADDRESS + 4))

或者这是用括号过度杀戮,只是不需要?
不需要外支架。
内支架很重要。如果没有括号,cast将比addition具有更高的优先级。然后,您不会向地址中添加4个字节,而是添加4个内存对象的大小(此处为16个字节)。