u-boot移植随笔:一些内存地址的再次研究(二维数组及指针数组)

本文涉及大量内存地址及十六进制数据。无耐性及无此爱好者可飘过。

说明:

以PC平台为参照,以C语言二维数组及指针数组为对象,测试u-boot中的内存地址及数据。所有数据从Secure CRT上复制得到,绝无人工干预,天然绿色产品,可信度极高。文本涉及代码及数据均以学习研究为目的,代码非实际使用,不作权威解释,任何后果概与山人无关。

 

山人对指针的指针有莫名的恐惧,尤其自身水平不高情况下。而且,绝口不谈一些计算机科学的著名名词,对那些算法、数据结构、需求分析、设计模式、程序设计、部署等等名词亦有恐惧(学习数据结构阴影至今仍在),因而基本上平时绝口不提。

时过境迁,如今山人也有一定的编码经验,对那些教材中出现的代码亦有自己的认识,对i+++++i这类形式的题目也有清醒的认识。

 

闲话休提,上代码:

#include <common.h>
#include <command.h>

int a[2][2] = {
        {3,56},
        {15,73},
};

char *b[] = {
         "linux",
         "windows",
         "mac os",
};

char *c[][2] = {
        { "linux""unix"},
        { "windows"},
        { "mac os"},
};

int do_pointer_test(cmd_tbl_t *cmdtp,  int flag,  int argc,  char *  const argv[])
{
         int i;
        printf( "sizeof a: %d sizeof b: %d sizeof c: %d/n/n"sizeof(a),  sizeof(b),  sizeof(c));
         for (i=0;i< sizeof(a)/ sizeof( int);i++)
                printf( "%p %p: %d/t %p: %d %p/n", a+i, *a+i, *(*a+i), a[i], *a[i], ( void*)*a[i]);
        printf( "/n");
        printf( "&b[i] b+i b[i] b[i] *b+i/n");
         for (i=0;i< sizeof(b)/ sizeof( char*);i++)
                printf( "%p %p %p: %s/t %s/n", &b[i], b+i, b[i], b[i], *b+i);

        printf( "/n");
         for (i=0;i< sizeof(c)/ sizeof( char*);i++)
                printf( "%p %p: %s/n", c[i], *c[i], *c[i]);
        printf( "/n");
         return 0;
}

U_BOOT_CMD(
        pointer_test, 2, 1,do_pointer_test,
         "just a test of my own",
         "nothing"
);

 

在u-boot命令行下测试结果:

LATE2440  $ pointer_test
sizeof a: 16 sizeof b: 12 sizeof c: 24

33fa622c 33fa622c: 3     33fa622c: 3 00000003
33fa6234 33fa6230: 56    33fa6234: 15 0000000f
33fa623c 33fa6234: 15    33fa623c: 872036659 33fa3933
33fa6244 33fa6238: 73    33fa6244: 872038649 33fa40f9

&b [i]      b+i      b[i]       b[i]      *b+i
33fa623c 33fa623c 33fa3933: linux        linux
33fa6240 33fa6240 33fa40f1: windows      inux
33fa6244 33fa6244 33fa40f9: mac os       nux

33fa6248 33fa3933: linux
33fa6250 33fa40f1: windows
33fa6258 33fa40f9: mac os
(此处死机)

 

数组a的大小好确认:4(成员个数)*4(int类型大小) = 16;数组b也好确认:3(成员个数)*4(指针大小) = 12;数组c是一个二维数组,元素为一指针,3组,每组2个元素,共6个元素,指针大小为4,因此大小为:6*4 = 24。

 

现在查看一下数组a所在的地址:

LATE2440  $ md.b 33fa622c
33fa622c: 03 00 00 00 38 00 00 00 0f 00 00 00 49 00 00 00    ....8.......I...
33fa623c: 33 39 fa 33 f1 40 fa 33 f9 40 fa 33 33 39 fa 33    39.3.@.3.@.339.3
33fa624c: 00 41 fa 33 f1 40 fa 33 00 00 00 00 f9 40 fa 33    .A.3.@.3.....@.3
33fa625c: 00 00 00 00 08 08 08 08 08 08 08 08 08 28 28 28    .............(((

 

其后有4个元素,分别为3、38、f和49,变成十进制则是3、56、15和73。

 

下面看一下数组b的地址:

LATE2440  $ md.b 33fa623c
33fa623c: 33 39 fa 33 f1 40 fa 33 f9 40 fa 33 33 39 fa 33    39.3.@.3.@.339.3
33fa624c: 00 41 fa 33 f1 40 fa 33 00 00 00 00 f9 40 fa 33    .A.3.@.3.....@.3
33fa625c: 00 00 00 00 08 08 08 08 08 08 08 08 08 28 28 28    .............(((
33fa626c: 28 28 08 08 08 08 08 08 08 08 08 08 08 08 08 08    ((..............

 

前面三个地址分别为:33fa3933、33fa40f1和33fa40f9,就是b[0]、b[1]和b[2]的地址,再看看这些地址:

LATE2440  $ md.b 33fa3933
33fa3933: 6c 69 6e 75 78 00 4c 69 6e 75 78 00 6e 65 74 62    linux.Linux.netb
33fa3943: 73 64 00 4e 65 74 42 53 44 00 72 74 65 6d 73 00    sd.NetBSD.rtems.
33fa3953: 52 54 45 4d 53 00 75 2d 62 6f 6f 74 00 55 2d 42    RTEMS.u-boot.U-B
33fa3963: 6f 6f 74 00 71 6e 78 00 51 4e 58 00 76 78 77 6f    oot.qnx.QNX.vxwo

第一个字符串便是“linux”。

 

LATE2440  $ md.b 33fa40f1
33fa40f1: 77 69 6e 64 6f 77 73 00 6d 61 63 20 6f 73 00 75    windows.mac os.u
33fa4101: 6e 69 78 00 70 6f 69 6e 74 65 72 5f 74 65 73 74    nix.pointer_test
33fa4111: 00 25 6c 6c 75 20 42 79 74 65 73 25 73 00 2e 25    . %llu Bytes %s..%
33fa4121: 6c 64 00 20 25 63 69 42 25 73 00 20 25 30 2a 78    ld.  %ciB %s.  %0*x

前面两个字符串就是“windows”和“mac os”。

后面我们可以看到,在PC平台上,三者其实是紧挨在一起的。这里只有后两个字符串是在一起(33fa40f1+8 = 33fa40f9)。这里我们也可以看到字符串在内存中是以“/0”结尾的(如“windows.”后的点号,实际数据是0),不过在代码上体现不出来。以后我们要注意,在内存分配时需要对字符串(指针)额外关照,至少要分配多一个字节给它。

不过我们也看到了,这三个字符串前面后面都有字符串(u-boot本身的),如:

LATE2440  $ md.b 33fa3900
33fa3900: 52 43 20 36 34 20 42 69 74 00 62 6c 61 63 6b 66    RC 64 Bit.blackf
33fa3910: 69 6e 00 42 6c 61 63 6b 66 69 6e 00 61 76 72 33    in.Blackfin.avr3
33fa3920: 32 00 41 56 52 33 32 00 49 6e 76 61 6c 69 64 20    2.AVR32.Invalid 
33fa3930: 4f 53 00 6c 69 6e 75 78 00 4c 69 6e 75 78 00 6e    OS.linux.Linux.n

LATE2440  $ md.b 33fa40e0
33fa40e0: 09 20 25 73 0a 00 25 70 20 25 70 3a 20 25 73 0a    .  %s.. %p  %p%s.
33fa40f0: 00 77 69 6e 64 6f 77 73 00 6d 61 63 20 6f 73 00    .windows.mac os.
33fa4100: 75 6e 69 78 00 70 6f 69 6e 74 65 72 5f 74 65 73    unix.pointer_tes
33fa4110: 74 00 25 6c 6c 75 20 42 79 74 65 73 25 73 00 2e    t. %llu Bytes %s..

 

这说明了它们占领了别人的“领域”,而且,在测试结果中我们意外地看到,*a[3]和*a[4]分别是b[0]和b[2]的地址,限于能力,这里不作解释,留日后技术提高了再研究。

 

下面是在PC平台(fedora9)的测试结果:

[latelee@FightNow linux-cc] $ ./a.out
sizeof a: 16 sizeof b: 12 sizeof c: 24

0x80498e4 0x80498e4: 3   0x80498e4: 3 0x3
0x80498ec 0x80498e8: 56  0x80498ec: 15 0xf
0x80498f4 0x80498ec: 15  0x80498f4: 134514372 0x80486c4
0x80498fc 0x80498f0: 73  0x80498fc: 134514386 0x80486d2

&b [i]       b+i      b[i]       b[i]  *b+i
0x80498f4 0x80498f4 0x80486c4: linux     linux
0x80498f8 0x80498f8 0x80486ca: windows   inux
0x80498fc 0x80498fc 0x80486d2: mac os    nux

0x8049900 0x80486c4: linux
0x8049908 0x80486ca: windows
0x8049910 0x80486d2: mac os
0x8049918 (nil): (null)
0x8049920 (nil): (null)
0x8049928 (nil): (null)

 

最后几行都打印了null,因为这的确是没有数据的,不过在u-boot中就死机了。

 

用gdb查看:

(gdb) p b
$4 = {0x80486c4  "linux", 0x80486ca  "windows", 0x80486d2  "mac os"}

(gdb) p c
$1 = {{0x80486c4  "linux", 0x80486d9  "unix"}, {0x80486ca  "windows", 0x0}, {
    0x80486d2  "mac os", 0x0}}
(gdb) 

(gdb) p &b
$5 = (char *(*) [3]) 0x80498f4

(gdb) p &a
$6 = (int (*) [2][2]) 0x80498e4
(gdb) p &a [1][1]
$9 = (int *) 0x80498f0
(gdb) p a [1][1]
$10 = 73
(gdb) p &a [1]
$12 = (int (*) [2]) 0x80498ec
(gdb) p a [1]
$13 = {15, 73}
(gdb) 

PS:对于元素的访问,array[i]与array+i不太一样,跟具体类型有关,这从代码中亦能看出来。

写这篇文章的原因是在CU论坛上看到有人在讨论二维数组的帖子。看了一下他们的讨论,发现自己啥也不懂,于是借助u-boot来看看,结果发现,自己真的是不太懂。原来自己已经很久没有看C语言的书籍了。看来最近忙着移植,没时间看书了,一些基本概念也不清楚了。身为一个代码工人,除了表示惭愧外,要努力学习了。

                                                                                                                                  山人记于即日

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值