跳至主要内容

【转】vivi开发笔记【专辑】


文章说明:calmarrow(lqm)原创

文章引自:http://piaoxiang.cublog.cn

 
2007-07-21
 
    今天把vivi编译了一下,顺便解决了几个问题。算是初步工作吧,下一步打算读vivi的源代码,然后改造一下,最后争取自己完成一个小的bootloader。
 
准备工作(这些都是基于EDUKIT-III教学平台,虽然开发工具上有些不同,但是原理和流程上是相同的。相信理解了嵌入式系统开发流程之后,对这些就会有很清晰的认识):
 
1)下载Nand_Prog.ide.bin到nor flash。这步工作是为烧写nand flash做准备的。为什么不利用仿真器直接烧写nand flash呢?理解了JTAG的原理后,对这步工作不难理解。nand flash和nor flash是不同的,nand flash的烧写需要ECC算法等,比较复杂。现在的这个仿真器不支持,所以就不能利用JTAG来直接烧写了。当然,如果在仿真器支持软件中加入对nand flash烧写的支持,这步工作就省去了。就我所知,国内foxICE已经可以支持直接烧写nand flash了。
 
2)开发环境
    还是windowsXP+VMware+redhat 9。原来学习at91rm9200的时候,开发环境都已经搭建好了,开发工具也比较齐全。
 
3)目标
    移植好的vivi能支持从nand flash启动,测试内置的命令正常,利用开发板原来的内核映象和文件系统能够跑起来。vivi毕竟是一个比较小巧的bootloader,功能有限,使用上可能有不方便的地方,所以,可以考虑在此基础上,读源代码,然后增加tftp下载功能。
 
开始工作
 
1)下载vivi
 
   我使用EDUKIT-III光盘中提供的vivi-20060929.tar.gz。解压不必细说,下面就开始修改。下面的修改方案是基于网上帖子,因为还没有仔细分析源代码,所以有些地方还不能理解清晰,这里的移植是为了获得直观的印象,如果要想得到技术水平的提升,那还是得深入分析vivi源代码,看看这一切究竟是如何完成的。
 
2)修改Makefile
    因为国内大部分S3C2410的设计都是抄袭smdk2410,所以vivi的移植相对来说,工作量很小,只需要更改开发工具的几个宏就可以了。当然,如果想要增加功能,则改动可能会大一点。
 
只要更改如下:
LINUX_INCLUDE_DIR -- 更改为交叉编译器的include文件夹
CROSS_COMPILE     -- 交叉编译器的可执行文件的路径
ARM_GCC_LIBS      -- 交叉编译器的lib库文件的路径
 

################## Modified Start ####################################
# Data : 2007-07-21
# Modified by Liu Qingmin <piaoxiangxinling@163.com>

#
# change this to point to the Linux include directory
#

# orginal setup
#LINUX_INCLUDE_DIR = /opt/host/armv4l/include/

# my setup
LINUX_INCLUDE_DIR = /usr/local/arm/2.95.3/include

################# Modified End ######################################

################## Modified Start ####################################
# Data : 2007-07-21
# Modified by Liu Qingmin <piaoxiangxinling@163.com>

# orginal setup
#CROSS_COMPILE = /opt/host/armv4l/bin/armv4l-redhat-linux-
#CROSS_COMPILE = /opt/host/armv4l/bin/armv4l-unknown-linux-

# my setup
CROSS_COMPILE = /usr/local/arm/2.95.3/bin/arm-linux-

################# Modified End ######################################

################## Modified Start ####################################
# Data : 2007-07-21
# Modified by Liu Qingmin <piaoxiangxinling@163.com>

#
# Location of the gcc arm libs.
#

# orginal setup
#ARM_GCC_LIBS = /opt/host/armv4l/lib/gcc-lib/armv4l-unknown-linux/2.95.2
#ARM_GCC_LIBS = /opt/host/armv4l/lib/gcc-lib/armv4l-redhat-linux/2.95.3

# my setup
ARM_GCC_LIBS = /usr/local/arm/2.95.3/lib/gcc-lib/arm-linux/2.95.3

################# Modified End ######################################

 
    这些都比较简单。
 
3)修改arch/s3c2410/smdk.c
    主要是修改nand flash分区信息。
 

#ifdef CONFIG_S3C2410_NAND_BOOT
mtd_partition_t default_mtd_partitions[] = {
        {
                name:           "vivi",         /* 128K, 1-8 sector             */
                offset:         0,
                size:           0x00020000,
                flag:           0
        }, {
                name:           "param",        /* 64K, 9-12 sector             */
                offset:         0x00020000,
                size:           0x00010000,
                flag:           0
        }, {
                name:           "kernel",       /* 2M+832K, 12-192 setctor      */
                offset:         0x00030000,
                size:           0x002d0000,
                flag:           0
        }, {
                name:           "root",         /* 29M, 193-2048 sector         */
                offset:         0x00300000,
                size:           0x01d00000,
                flag:           MF_BONFS
        }
};

 
    这里遇到了bon分区与mtd分区的疑惑,在分析vivi源代码时在深入分析。上面文件配置的只是mtd分区,这个可以用part show来查看。
 
4)编译烧写
 
    写个简单的批处理脚本procedure。以便后续工作的方便。【后来发现,vivi本身就提供了这样的操作,所以这个小的脚本是没有必要编写的。这一点会在Makefile分析时给出】
 

[root@lqm vivi]# cat procedure
#!/bin/sh

make myboard_config && make oldconfig && make vivi && cp -f vivi /mnt/hgfs/common/

   
    烧写vivi,正常。但是蜂鸣器一直在响。于是想在vivi中添加代码,关掉蜂鸣器,同时利用开发板上的四个指示灯做一个跑马灯的小程序。于是修改arch/s3c2410/head.S:
 

@@@@@@@@@@@@@@@@@@ Modified Start @@@@@@@@@@@@@@@@@@@@@
        mov r0, #10               @ rotate 10 times
loop:
        mov r2, #0xdf             @ D1205 led on
        str r2, [r1, #oGPIO_DAT]
        bl delay

        mov r2, #0x7f             @ D1207 led on
        str r2, [r1, #oGPIO_DAT]
        bl delay

        mov r2, #0xef             @ D1204 led on
        str r2, [r1, #oGPIO_DAT]
        bl delay

        mov r2, #0xbf             @ D1206 led on
        str r2, [r1, #oGPIO_DAT]
        bl delay

        subs r0, r0, #1
        bne loop

        mov r2, #0x0f             @ all leds on
        str r2, [r1, #oGPIO_DAT]

        @ buzzer off
        ldr r1, =0x56000010 @ GPBCON
        ldr r2, =0x155559
        str r2, [r1]
        ldr r2, =0x7ff
        str r2, [r1, #8]
        orr r2, r2, #0x01         @ buzzer off when high voltage(PWM1)
        str r2, [r1, #4]
@@@@@@@@@@@@@@@@@@ Modified End @@@@@@@@@@@@@@@@@@@@@@@@@


/*
 * subroutines
 */

@@@@@@@@@@@@@@@@@@ Modified Start @@@@@@@@@@@@@@@@@@@@@
@
@ led delay
@
delay:
        ldr r3, =0x00080000
wait:
        subs r3, r3, #1
        bne wait

        mov pc, lr

@@@@@@@@@@@@@@@@@@ Modified End @@@@@@@@@@@@@@@@@@@@@

 
    通过source insight查看代码,可以分析出第一条打印信息的来源init/version.c。这样,just for fun,可以添加自己的启动信息。主要的参数都是有Makefile来完成的,读一下Makefile的代码,不难发现。
 

[root@lqm init]# cat version.c
/*
 * vivi/lib/version.c
 */


#include "version.h"
#include "compile.h"

const char *vivi_banner =
                       "\n\r\t\t^_^ Well done, boy! Go on --> \n\r\n\r"
                       "VIVI version " VIVI_RELEASE " (" VIVI_COMPILE_BY "@"
                       VIVI_COMPILE_HOST ") (" VIVI_COMPILER ") " UTS_VERSION "\n\r";

 
【注:这里还有个小问题。就是在这里添加的时候,\n\r要合起来用,不能只用\n。原因如下:
 
    计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。
 
    于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做"回车",告诉打字机把打印头定位在左边界;另一个叫做"换行",告诉打字机把纸向下移一行。
 
    这就是"换行"和"回车"的来历,从它们的英语名字上也可以看出一二。
 
    后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。Unix 系统里,每行结尾只有"<换行>",即"\n";Windows系统里面,每行结尾是"<换行><回车>",即"\ n\r";Mac系统里,每行结尾是"<回车>"。一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。
 
    这几个地方我都遇到过,不过一直没有搞清楚。现在才算是找到根源了。】
 
    添加完成,重新执行procedure。完成烧写,测试如下:
 

^_^ Well done, Go on -->

VIVI version 0.1.4 (root@lqm) (gcc version 2.95.3 20010315 (release)) #0.1.4 日 7月 22 10:15:15 CST 2007
MMU table base address = 0x33DFC000
Succeed memory mapping.
NAND device: Manufacture ID: 0xec, Chip ID: 0x75 (Samsung KM29U256T)
Could not found stored vivi parameters. Use default vivi parameters.
Press Return to start the LINUX now, any other key for vivi
type "help" for help.
vivi> part show
mtdpart info. (4 partitions)
name offset size flag
------------------------------------------------
vivi : 0x00000000 0x00020000 0 128k
param : 0x00020000 0x00010000 0 64k
kernel : 0x00030000 0x002d0000 0 2M+832k
root : 0x00300000 0x01d00000 4 29M
vivi>

   
    然后执行bon分区:
 

vivi> bon part 0 192K 3M
doing partition
offset = 0
flag = 0
offset = 196608
flag = 0
offset = 3145728
flag = 0
check bad block
part = 0 end = 196608
part = 1 end = 3145728
part = 2 end = 33554432
part0:
        offset = 0
        size = 196608
        bad_block = 0
part1:
        offset = 196608
        size = 2949120
        bad_block = 0
part2:
        offset = 3145728
        size = 30392320
        bad_block = 0
vivi>

 
    重新烧写vivi,注意这个时候不要断电。
 

vivi> load flash vivi x
Ready for downloading using xmodem...
Waiting...

正在开始 xmodem 传输。 按 Ctrl+C 取消。
正在传输 vivi...
  100% 67 KB 6 KB/s 00:00:10 0 错误

Downloaded file at 0x30000000, size = 69376 bytes
Found block size = 0x00014000
Erasing... ... done
Writing... ... done
Written 69376 bytes
vivi>

 
    检查分区情况:

vivi> part show
mtdpart info. (4 partitions)
name offset size flag
------------------------------------------------
vivi : 0x00000000 0x00020000 0 128k
param : 0x00020000 0x00010000 0 64k
kernel : 0x00030000 0x002d0000 0 2M+832k
root : 0x00300000 0x01d00000 4 29M
vivi> bon part show
BON info. (3 partitions)
No: offset size flags bad
---------------------------------------------
 0: 0x00000000 0x00030000 00000000 0 192k
 1: 0x00030000 0x002d0000 00000000 0 2M+832k
 2: 0x00300000 0x01cfc000 00000000 0 28M+1008k
vivi>

 
    其中,part show显示的是mtd分区信息,跟smdk.c文件的配置相同。bon part show显示的bon分区信息,注意到最后一个分区少了一个扇区16K,因为bon命令把bon分区信息表存储在最后一个扇区了。
 
    烧写内核映象和文件系统:
 

vivi> load flash kernel x
Ready for downloading using xmodem...
Waiting...

正在开始 xmodem 传输。 按 Ctrl+C 取消。
正在传输 zImage...
  100% 646 KB 7 KB/s 00:01:25 0 错误

Downloaded file at 0x30000000, size = 661760 bytes
Found block size = 0x000a4000
Erasing... ... done
Writing... ... done
Written 661760 bytes
vivi> ?

                ^_^ Well done, Go on -->

VIVI version 0.1.4 (root@lqm) (gcc version 2.95.3 20010315 (release)) #0.1.4 日 7月 22 10:15:15 CST 2007
MMU table base address = 0x33DFC000
Succeed memory mapping.
NAND device: Manufacture ID: 0xec, Chip ID: 0x75 (Samsung KM29U256T)
Found saved vivi parameters.
Press Return to start the LINUX now, any other key for vivi
Copy linux kernel from 0x00030000 to 0x30008000, size = 0x002d0000 ... done
zImage magic = 0x016f2818
Setup linux parameters at 0x30000100
linux command line is: "noinitrd root=/dev/bon/2 init=/linuxrc console=ttyS0"
MACH_TYPE = 193
NOW, Booting Linux......
Uncompressing Linux............................................... done, booting the kernel.
Linux version 2.4.18-rmk7-pxa1 (root@lqm) (gcc version 2.95.3 20010315 (release)) #1 Fri Jul 20 15:12:44 CST 2007
CPU: ARM/CIRRUS Arm920Tsid(wb) revision 0
Machine: Embest EduKit II (S3C2410x)
On node 0 totalpages: 16384
zone(0): 16384 pages.
zone(1): 0 pages.
zone(2): 0 pages.
Kernel command line: noinitrd root=/dev/bon/2 init=/linuxrc console=ttyS0
DEBUG: timer count 15626
Console: colour dummy device 80x30
Calibrating delay loop... 99.94 BogoMIPS
Memory: 64MB = 64MB total
Memory: 62880KB available (1229K code, 296K data, 60K init)
Dentry-cache hash table entries: 8192 (order: 4, 65536 bytes)
Inode-cache hash table entries: 4096 (order: 3, 32768 bytes)
Mount-cache hash table entries: 1024 (order: 1, 8192 bytes)
Buffer-cache hash table entries: 4096 (order: 2, 16384 bytes)
Page-cache hash table entries: 16384 (order: 4, 65536 bytes)
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
Initializing RT netlink socket
CPU clock = 200.000 Mhz, HCLK = 100.000 Mhz, PCLK = 50.000 Mhz
Starting kswapd
devfs: v1.10 (20020120) Richard Gooch (rgooch@atnf.csiro.au)
devfs: boot_options: 0x1
ttyS%d0 at I/O 0x50000000 (irq = 52) is a S3C2410
ttyS%d1 at I/O 0x50004000 (irq = 55) is a S3C2410
ttyS%d2 at I/O 0x50008000 (irq = 58) is a S3C2410
Console: switching to colour frame buffer device 30x40
Installed S3C2410 frame buffer
pty: 256 Unix98 ptys configured
s3c2410-ts initialized
S3C2410 Real Time Clock Driver v0.1
block: 128 slots per queue, batch=32
eth0: cs8900 rev K(3.3 Volts) found at 0xd0000300
cs89x0 media RJ-45, IRQ 37
NAND device: Manufacture ID: 0xec, Chip ID: 0x75 (Samsung KM29U256T)
bon0: 00000000-00030000 (00030000) 00000000
bon1: 00030000-00300000 (002d0000) 00000000
bon2: 00300000-01ffc000 (01cfc000) 00000000
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP, IGMP
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 4096 bind 4096)
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
NetWinder Floating Point Emulator V0.95 (c) 1998-1999 Rebel.com
cramfs: wrong magic
FAT: bogus logical sector size 65535
Kernel panic: VFS: Unable to mount root fs on 61:02


vivi> load flash root x
Ready for downloading using xmodem...
Waiting...

正在开始 xmodem 传输。 按 Ctrl+C 取消。
正在传输 root.cramfs...
  100% 1104 KB 7 KB/s 00:02:22 0 错误

Downloaded file at 0x30000000, size = 1130496 bytes
Found block size = 0x00114000
Writing... size = 1130496
bad_block = 0
 ... done
Written 1130496 bytes
vivi>

vivi>

                ^_^ Well done, Go on -->

VIVI version 0.1.4 (root@lqm) (gcc version 2.95.3 20010315 (release)) #0.1.4 日 7月 22 10:15:15 CST 2007
MMU table base address = 0x33DFC000
Succeed memory mapping.
NAND device: Manufacture ID: 0xec, Chip ID: 0x75 (Samsung KM29U256T)
Found saved vivi parameters.
Press Return to start the LINUX now, any other key for vivi
Copy linux kernel from 0x00030000 to 0x30008000, size = 0x002d0000 ... done
zImage magic = 0x016f2818
Setup linux parameters at 0x30000100
linux command line is: "noinitrd root=/dev/bon/2 init=/linuxrc console=ttyS0"
MACH_TYPE = 193
NOW, Booting Linux......
Uncompressing Linux............................................... done, booting the kernel.
Linux version 2.4.18-rmk7-pxa1 (root@lqm) (gcc version 2.95.3 20010315 (release)) #1 Fri Jul 20 15:12:44 CST 2007
CPU: ARM/CIRRUS Arm920Tsid(wb) revision 0
Machine: Embest EduKit II (S3C2410x)
On node 0 totalpages: 16384
zone(0): 16384 pages.
zone(1): 0 pages.
zone(2): 0 pages.
Kernel command line: noinitrd root=/dev/bon/2 init=/linuxrc console=ttyS0
DEBUG: timer count 15626
Console: colour dummy device 80x30
Calibrating delay loop... 99.94 BogoMIPS
Memory: 64MB = 64MB total
Memory: 62880KB available (1229K code, 296K data, 60K init)
Dentry-cache hash table entries: 8192 (order: 4, 65536 bytes)
Inode-cache hash table entries: 4096 (order: 3, 32768 bytes)
Mount-cache hash table entries: 1024 (order: 1, 8192 bytes)
Buffer-cache hash table entries: 4096 (order: 2, 16384 bytes)
Page-cache hash table entries: 16384 (order: 4, 65536 bytes)
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
Initializing RT netlink socket
CPU clock = 200.000 Mhz, HCLK = 100.000 Mhz, PCLK = 50.000 Mhz
Starting kswapd
devfs: v1.10 (20020120) Richard Gooch (rgooch@atnf.csiro.au)
devfs: boot_options: 0x1
ttyS%d0 at I/O 0x50000000 (irq = 52) is a S3C2410
ttyS%d1 at I/O 0x50004000 (irq = 55) is a S3C2410
ttyS%d2 at I/O 0x50008000 (irq = 58) is a S3C2410
Console: switching to colour frame buffer device 30x40
Installed S3C2410 frame buffer
pty: 256 Unix98 ptys configured
s3c2410-ts initialized
S3C2410 Real Time Clock Driver v0.1
block: 128 slots per queue, batch=32
eth0: cs8900 rev K(3.3 Volts) found at 0xd0000300
cs89x0 media RJ-45, IRQ 37
NAND device: Manufacture ID: 0xec, Chip ID: 0x75 (Samsung KM29U256T)
bon0: 00000000-00030000 (00030000) 00000000
bon1: 00030000-00300000 (002d0000) 00000000
bon2: 00300000-01ffc000 (01cfc000) 00000000
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP, IGMP
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 4096 bind 4096)
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
NetWinder Floating Point Emulator V0.95 (c) 1998-1999 Rebel.com
VFS: Mounted root (cramfs filesystem).
Mounted devfs on /dev
Freeing init memory: 60K
mount /etc as ramfs
re-create the /etc/mtab entries
init started: BusyBox v1.00 (2005.06.09-02:02+0000) multi-call binary
Starting pid 17, console /dev/console: '/etc/init.d/rcS'
 
Embest Embedded Linux Development Paltform.
 
Default board ip: 192.192.192.190
To change the ip addr: ifconfig eth0 new_board_ip
 
Start the web server: http:
//(board_ip)/index.htm

To connect the NFS server, please type like:
   mkdir /etc/var/nfs
   mount -t nfs nfs_server_ip:/home/app /etc/var/nfs -o nolock
To use the USB disc(insert first), please type like:
   mount /dev/sda /mnt/udisk _OR_ mount /dev/sda1 /mnt/udisk

Please press Enter to activate this console.
Starting pid 42, console /dev/console: '/bin/sh'
~ # ls
bin etc linuxrc proc tmp var
dev lib mnt sbin usr
~ #

 
    一切正常。

评论

此博客中的热门博文

【转】cs8900网卡的移植至基于linux2.6内核的s3c2410平台

cs8900网卡的移植至基于linux2.6内核的s3c2410平台(转) 2008-03-11 20:58 硬件环境:SBC-2410X开发板(CPU:S3C2410X) 内核版本:2.6.11.1 运行环境:Debian2.6.8 交叉编译环境:gcc-3.3.4-glibc-2.3.3 第一部分 网卡CS8900A驱动程序的移植 一、从网上将Linux内核源代码下载到本机上,并将其解压: #tar jxf linux-2.6.11.1.tar.bz2 二、打开内核顶层目录中的Makefile文件,这个文件中需要修改的内容包括以下两个方面。 (1)指定目标平台。 移植前:         ARCH?= $(SUBARCH) 移植后: ARCH            :=arm (2)指定交叉编译器。 移植前: CROSS_COMPILE ?= 移植后: CROSS_COMPILE   :=/opt/crosstool/arm-s3c2410-linux-gnu/gcc-3.3.4-glibc-2.3.3/bin/arm-s3c2410-linux-gnu- 注:这里假设编译器就放在本机的那个目录下。 三、添加驱动程序源代码,这涉及到以下几个方面。(1)、从网上下载了cs8900.c和cs8900.h两个针对2.6.7的内核的驱动程序源代码,将其放在drivers/net/arm/目录下面。 #cp cs8900.c ./drivers/net/arm/ #cp cs8900.h ./drivers/net/arm/ 并在cs8900_probe()函数中,memset (&priv,0,sizeof (cs8900_t));函数之后添加如下两条语句: __raw_writel(0x2211d110,S3C2410_BWSCON); __raw_writel(0x1f7c,S3C2410_BANKCON3); 注:其原因在"第二部分"解释。 (2)、修改drivers/net/arm/目录下的Kconfig文件,在最后添加如...

【转】s3c2410 MMU

作者:蔡于清 www.another-prj.com MMU ,全称Memory Manage Unit, 中文名――存储器管理单元。 许多年以前,当人们还在使用DOS或是更古老的操作系统的时候,计算机的内存还非常小,一般都是以K为单位进行计算,相应的,当时的程序规模也不大,所以内存容量虽然小,但还是可以容纳当时的程序。但随着图形界面的兴起还用用户需求的不断增大,应用程序的规模也随之膨胀起来,终于一个难题出现在程序员的面前,那就是应用程序太大以至于内存容纳不下该程序,通常解决的办法是把程序分割成许多称为 覆盖块(overlay) 的片段。覆盖块0首先运行,结束时他将调用另一个覆盖块。虽然覆盖块的交换是由OS完成的,但是必须先由程序员把程序先进行分割,这是一个费时费力的工作,而且相当枯燥。人们必须找到更好的办法从根本上解决这个问题。不久人们找到了一个办法,这就是 虚拟存储器(virtual memory). 虚拟存储器的基本思想是程序,数据,堆栈的总的大小可以超过物理存储器的大小,操作系统把当前使用的部分保留在内存中,而把其他未被使用的部分保存在磁盘上。 比如对一个16MB的程序和一个内存只有4MB的机器,OS通过选择,可以决定各个时刻将哪4M的内容保留在内存中,并在需要时在内存和磁盘间交换程序片段,这样就可以把这个16M的程序运行在一个只具有4M内存机器上了。而这个16M的程序在运行前不必由程序员进行分割。 任何时候,计算机上都存在一个程序能够产生的地址集合,我们称之为 地址范围 。 这个范围的大小由CPU的位数决定 ,例如一个32位的CPU,它的地址范围是0~0xFFFFFFFF (4G),而对于一个64位的CPU,它的地址范围为0~0xFFFFFFFFFFFFFFFF (64T).这个范围就是我们的程序能够产生的地址范围,我们把这个地址范围称为 虚拟地址空间 ,该空间中的某一个地址我们称之为 虚拟地址 。与虚拟地址空间和虚拟地址相对应的则是 物理地址空间 和 物理地址 ,大多数时候我们的系统所具备的 物理地址空间只是虚拟地址空间的一个子集 ,这里举一个最简单的例子直观地说明这两者,对于一台内存为256MB的32bit x86主机来说,它的虚拟地址空间范围是0~0xFFFFFFFF(4G),而物理地址空间范围是0x000000000~0x0FFFFFFF(256...

【转】函数指针和指针函数

【函数指针】        在程序运行中,函数代码是程序的算法指令部分,它们和数组一样也占用存储空间,都有相应的地址。可以使用指针变量指向数组的首地址,也可以使用指针变量指向函数代码的首地址,指向函数代码首地址的指针变量称为函数指针。 1.函数指针定义 函数类型 (*指针变量名)(形参列表); "函数类型"说明函数的返回类型,由于"()"的优先级高于"*",所以指针变量名外的括号必不可少,后面的"形参列表"表示指针变量指向的函数所带的参数列表。 例如: int (*f)(int x); double (*ptr)(double x); 在定义函数指针时请注意:     函数指针和它指向的函数的参数个数和类型都应该是―致的; 函数指针的类型和函数的返回值类型也必须是一致的。 2.函数指针的赋值 函数名和数组名一样代表了函数代码的首地址,因此在赋值时,直接将函数指针指向函数名就行了。 例如, int func(int x);   /* 声明一个函数 */ int (*f) (int x);    /* 声明一个函数指针 */ f=func;            /* 将func函数的首地址赋给指针f */ 赋值时函数func不带括号,也不带参数,由于func代表函数的首地址,因此经过赋值以后,指针f就指向函数func(x)的代码的首地址。 3.通过函数指针调用函数 函数指针是通过函数名及有关参数进行调用的。 与其他指针变量相类似,如果指针变量pi是指向某整型变量i的指针,则*p等于它所指的变量i;如果pf是指向某浮点型变量f的指针,则*pf就等价于它所指的变量f。同样地,*f是指向函数func(x)的指针,则*f就代表它所指向的函数func。所以在执行了f=func;之后,(*f)和func代表同一函数。 由于函数指针指向存储区中的某个函数,因此可以通过函数指针调用相应的函数。现在我们就讨论如何用函数指针调用函数,它应执行下面三步: 首先,要说明函数指针变量。 例如:int (*f)...