关于指针地址+1的问题

在理解S3C6410 MMU的地址映射的时候,竟然被地址加1的问题给卡住了。

 

先贴源代码

1

2

3

4

5

6

7

8

9

10

11

12

13

void create_page_table(void)

{

    unsigned long *ttb = (unsigned long *)0x50000000;

    unsigned long vaddr, paddr;

    vaddr = 0x50000000;

    paddr = 0x50000000;

    while (vaddr < 0x54000000)

    {

           *(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000)      

           vaddr += 0x100000;

           paddr += 0x100000;

    }

}

这里ttb是第一级表的首地址,为外部内存的首地址,S3C64100x50000000。然后建立一个映射表。

while第一次循环的时候,vaddr>>20 0x500,就相当于往0x50000500写入后面的数据,执行第二次的时候,vaddr>>200x501,就相当于往0x50000501写入后面的数据。等等,问题来了,arm对地址要求是4字节对齐的,怎么会有0x50000501这个地址了。

肯定是什么地方出现问题,但是代码是没有问题的,看来就是自己理解的问题。

最后,在别人的帮助下,才发现问题的所在。

原来地址加1和数据加1是不一样的。地址加1,要看是什么数据类型,不同的数据类型加的值不一样,对于int而言,地址加1就相当于地址加4。而数据加1就是单纯的数据加1

这里ttbunsigned long的指针,是占4个字节的。所以ttb在加1的时候,其实是会加4的,而加常数n的话,其实是会加n*4的。

循环第一次,vaddr >> 20的值为0x500,因为是和指针ttb相加,所以这个值要先乘以4在和ttb相加。0x500 * 4 = 0x1400。然后再和ttb相加,这个时候加的结果为0x50001400。这才是真正的地址,也是往这个地址写值的。循环第二次,vaddr >> 20的值0x501,因为是和指针ttb相加,所以这个值也先要先乘以4在和ttb相加。0x501 * 4 = 0x1404,在和ttb相加,这个时候加的结果为0x50001404。这个也才是真正的地址,也是往这个地址写值的。这样下来,写的地址才是4字节对齐的。

 

看来自己的C语言功底还不行啊。

VS仿真了看看。

1

2

3

4

5

6

7

8

9

10

11

12

13

int main(void)

{

       unsigned long *ttb = (unsigned long *)0x50000000;

       unsigned long *address;

       unsigned long vaddr = 0x50000000;

       unsigned long paddr = 0x50000000;

       while (vaddr < 0x54000000)

       {

              address = ttb + (vaddr >> 20);

vaddr += 0x100000;

              paddr += 0x100000;

       }

}

调试结果

循环第一次

clip_image001[6]

看出ttb + (vaddr >> 20)的值是0x50001400

 

循环第二次

clip_image003[6]

看出ttb + (vaddr >> 20)的值是0x50001404

 

循环第三次

clip_image004[6]

看出ttb + (vaddr >> 20)的值是0x50001404

 

以前,学C语言的时候,书上说地址加常数的话,要看地址的类型,然后再把常数乘以类型的字节数在和地址相加,也没有注意这个细节。这个在这里可就遇到问题了。

所以说,地址和常数相加的时候,要看地址的数据类型是什么,然后再将乘数乘以类型的字节数,最后在和地址相加。

 

此条目发表在c/c++, 编程语言分类目录,贴了, , 标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。