问题
最近在学习uC/OS-III,刚好看到官方源码中的OSTaskStkInit函数中有这么一句让我百思不得其解。
/* Align the stack to 8-bytes. */
p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8);
然后我开始看CSDN其他博主的文章,然后我竟然开始怀疑官方是不是错了(too young,too naive)
看了很久的博主才终于明白,最后顺便写了下面这两遍博客,里面是关于字节对齐问题更具体的解释:
字节对齐
【嵌入式】堆栈8字节对齐
分析
回到本文的重点
p_stk = (CPU_STK *)((CPU_STK)(p_stk) & 0xFFFFFFF8); 这一句代码其实也就是为了进行8字节对齐
所谓的“对齐”就是从0开始就把内存按照一定大小划分,那么这个地址就一定能被这个大小整除。
那是怎么做到的呢?
p_stk 其实是一个 8字节的指针,从汇编角度来看的话,在执行到这一句语句之前,p_stk 可能因为char,int等这些不是8字节的变量影响,导致p_stk并不在划分的边界,如图
这时我们需要把p_stk"抽象地"下移,实际上下图中间那块黑色区域还是p_stk的,而且还是存在的,只是我们为了对齐再也不会去使用它,就废弃了——所以可以把它抽象为下移。
而且栈我们是要求不能完全用光的,会留有一点点,所以不用去考虑它的结尾在哪里。
解释
那么怎么用代码实现“下移”呢?
像上面的分析一样,只要使这个地址能被对齐的大小整除就可以了,因为这个大小是8,所以用位运算就是:
(CPU_STK)(p_stk) & 0xFFFFFFF8
低三位清零就相当于除以8了。