- [mywiil] 顶了!! 08/21 03:34
- [musicvs] 呵呵,很久没来了~ 论坛已经被删除了,这种方式失败了,呵呵~ 06/05 23:39
- [hwenycocodq520] 哈哈,疯狂的程序员 我也看过,感觉越来越像小说里面的主人公 05/17 19:06
- [wind_asm] 一直有个地方不明白: *(char far *)(0xb8000000+160*10+80+a+a 05/09 17:03
- [jonytan] 不行呀! 找不到网页呢! 05/08 15:33
- [caicaihong] 想问一下,综合研究5中,怎么去找并且去判断%d和%c呢?我想了很久想不明白,希望你能给点提示。 04/20 18:10
- [fencebach] WE NEED TO WEEK UP 12/07 16:01
- [springaccount] 学着看英文小说……克服一段时间就过去了,回过头来再看一遍,即使你不能读懂全部也有百分之七八懂了FIG 10/16 17:33
- [springaccount] 大学学不到什么东西,但是如果你找得到目标我就觉得没白上了^__^Come on!!! 10/06 11:32
- [star999] 经历相似,希望一起崛起···· 09/28 11:42
- [zihaolee] 博主厉害~ 05/01 21:44
- [musicvs] 呵呵,它确实是以扇区为单位进行读写的,我也不懂怎么读写指定字节的数据,你是想实现什么功能呢? 12/14 14:07
- [mxl800] 最近很少在网上看到你了,过来问问题呀,不知道你什么时候来看! 我想问个关于int 13h中断的问题 12/14 08:50
- [musicvs] 恩恩,我看一看~ 11/26 12:21
- [mxl800] 呵呵,教我知识者,皆为吾师!musicvs老师,我又过来麻烦你了,不知道你会不会常来了,对于第十七章 11/26 09:10
- [musicvs] 呵呵,不过,不给跳着学... 11/12 23:54
- [grasshat] 哦,那我要等到下个学期了!c语言是学过的,下个阶段一个月足够了! 11/12 17:19
- [musicvs] 08年12月27日开始 11/12 16:37
- [grasshat] 我向问你下,你知道程序设计训练营什么时候进入下一个阶段吗? 11/12 07:53
- [musicvs] 我不是老师...这是"mxl800 "的一个"坏"习惯,老叫我们老师^_^ 11/06 20:20
[2008-10-07 12:07]
综合研究 研究试验5 函数如何接收不定数量的参数
第一个:研究下面的程序
void showchar(char a,int b);
main()
{
showchar('a',2);
}
void showchar(char a,int b)
{
*(char far *)(0xb8000000+160*10+80)=a;
*(char far *)(0xb8000000+160*10+81)=b;
}
问我们,main函数是如何给showchar传递参数的?showchar是如何接受参数.
从程序的汇编代码中可以看出,main函数是将要传递的参数入栈,而入栈的顺序是从最后一个参数开始的,这也正好让我们想到,showchar函数一定是通过出栈的方式取得参数的吧.哈,事实也是如此.
第二个问题:看下面的程序
void showchar(int,int,...);
main()
{
showchar(8,2,'a','b','c','d','e','f','g','h');
}
void showchar(int n,int color,...)
{
int a;
for (a=0;a!=n;a++)
{
*(char far *)(0xb8000000+160*10+80+a+a)=*(int *)(_BP+8+a+a);
*(char far *)(0xb8000000+160*10+81+a+a)=color;
}
}
王老师问我们,showchar函数是如何知道要显示多少个字符的?printf函数是如何知道有多少个参数的?
首先,看到这句void showchar(int,int,...); 就让我们想到,那个...省略号应该就是试验5的标题所写的不定量的参数了.
后面的showchar(8,2,'a','b','c','d','e','f','g','h');就是说有8个字符,而这些字符的颜色属性是2.
而for循环里面的当然就是向显存写入字符的ascii码和颜色属性了.
那showchar函数是如何知道要显示多少个字符的?
很明显,n就是说明了有8个字符了,但是具体是如何操作的呢?
关键就是这句代码了:
*(char far *)(0xb8000000+160*10+80+a+a)=*(int *)(_BP+8+a+a);
下面我就说说我的想法咯:
1.从debug中可以看到,程序中的数据段和栈段的段地址是相等的
2.*(int *)(_BP+8+a+a);就是相当于DS:[_BP+8+a+a]
3._BP+8是使DS:[_BP+8+a+a]最初指向存放字符a的内存单元.
4.a+a是干什么的呢?从for语句中可以看出,a+a是以偶数的方式递增的,即 0,2,4,6,8,10,12,14,16.
而当a+a=16即a=8时,不进行循环,所以我们只要看0,2,4,6,8,10,12,14这8种(刚好就是8个字符咯).
5.因为参数的传递是利用入栈的方式来进行的,所以一个字符是占据了一个字单元的空间的(原因是al中存放字符的ascii码,ah为0,而入栈的时候把整个ax入栈,所以就占了一个字单元的空间).
呵呵~到这里大家都知道了吧,为什么要用a+a?因为要使DS:[]指向每一个字符,所以每次加2,就指向下一个内存单元,也就是下一个字符了.
6.同样,这句话的0xb8000000+160*10+80+a+a,是用来指向下一个显存的内存单元的.
不过,还是有一个疑问,为什么在写程序的时候就知道要用_BP+8呢?
首先,最后入栈的参数是0002和0008,这里占了4个字节.然后在查看汇编代码时,才能知道,后面又进行了2次入栈操作,所以加起来就是8个字节,_BP+8就刚好能够指向字符'a'.
那,是不是有一个规律呢?
我发现:
1.每个函数的开始都会有这个2条指令
push bp
mov bp,sp
main函数里有,showchar函数里也有.
2.定义变量的时候,如果用int来定义变量,然后直接赋值的话,就跟试验3所说的一样,先分配一个空间,然后赋值的时候,用ds:[bp-02]的形式来指向变量的空间;
而如果是定义int变量之后,使用for语句,在for语句中给变量赋值.
如:
int a;
for (a=0;a!=n;a++)
那么,就会使用si寄存器来存放变量的值.
既然要用到si,那当然要先把si入栈,就像子程序一样,要用到什么寄存器,就把这些寄存器入栈,最后再出栈,以免修改了寄存器的内存.
所以,这里就有一个push si.
综合来说,
除了把字符参数入栈之外,还有4个入栈操作:0002和0008的入栈,push bp以及push si.(占8个字节)
所以,为了指向字符'a',就要使用_BP+8,然后为了循环指向字符a~h,就要使用_BP+8+a+a.
这就是*(int *)(_BP+8+a+a);的作用了...
哈,暂时研究到这里...后面再继续~^_^
(写了这么多,不知道大家会不会看不下去呢,嘻嘻~)
------------------------------------------------------------------
第一次编辑 2008年10月7日12:11:45
By 木头
------------------------------------------------------------------
******************************************************************
还有2个问题没有解决,就是上面问的:printf函数是如何知道有多少个参数的?
还有就是这个试验的第三问了:实现一个简单的printf函数,只需要支持"%c,%d"即可.
如果能知道printf函数是如何知道有多少个参数的话,第三问就差不多能解决了.
刚开始我以为可以仿照第二问的程序,用printf(...,int)这种方法,结果证明--我错了!
我又想,是不是用c语言中的字符串数组呢?但是无奈我的c语言功底实在是...(可以忽略).
不知道各位有什么方法解决第三问呢?希望能给我点提示...
------------------------------------------------------------------
第二次编辑 2008年10月8日19:55:53
By 木头
------------------------------------------------------------------
感谢一位朋友的提醒(可惜没有留名字)...我找到了我整个研究试验5的一个错误--我忽略了调用showchar函数时,会使用到call指令,而call指令会使IP入栈,从而,我以前所写的就错误了!
我还要几天要考试,就不把我的心得写出来了...如果有需要一起讨论的朋友,请加我QQ:357382814 谢谢~^_^
第三次编辑 2009年1月3日 20:39
By 木头
------------------------------------------------------------------
[ lwbfq 发表于 2008-10-08 17:50 ]
支持一下 呵呵
[ musicvs 发表于 2008-10-08 19:51 ]
呵呵~还没完成...
[ abob 发表于 2008-10-22 14:43 ]
用力的踩踩~~~
[ longhun 发表于 2008-10-28 10:26 ]
我还没学到。。。。。。等我遇到想不懂你再教我吧,先支持一下
[ mxl800 发表于 2008-11-26 09:05 ]
还没学到,我是过来问问题的
[ 游客 发表于 2008-12-30 21:59 ]
按博主对_BP+8的理解,是不能理解第一个问题的?
第一个问题对char a字符读取是_BP+4,但前面只有PUSH BP入栈,应该是_BP+2.为什么是_BP+4呢?
博主再仔细看一下第二个问题中SI是到底是用来干什么的?
(何况push si指令是在mov bp,sp的后面,是不会影响BP的值的.)
定义的整数型变量又放在哪了?
[ musicvs 发表于 2009-01-01 17:40 ]
谢谢楼上的...等我放假之后要再好好想想,下个星期考试,呵呵
[ musicvs 发表于 2009-01-03 20:34 ]
还是忍不住重新看了一遍,我找到了我错在哪了...非常感谢啊~
[ 游客 发表于 2009-02-27 20:49 ]
_BP寄存器默认的段是_SS,而不是博主说的_DS,博主该复习一下了
[ 游客 发表于 2009-06-02 22:20 ]
我的debug中数据段和栈段不是一样的,这是为什么呢?
直接运行可以成功显示,但是单步跟踪,只是显示空格
[ caicaihong 发表于 2010-04-20 18:10 ]
想问一下,综合研究5中,怎么去找并且去判断%d和%c呢?我想了很久想不明白,希望你能给点提示。
[ wind_asm 发表于 2010-05-09 17:03 ]
一直有个地方不明白:
*(char far *)(0xb8000000+160*10+80+a+a)=*(int *)(_BP+8+a+a);
为什么 前面是 char ,后面是int呢?
一个双字节的 数据怎么传给 单字节?