tc2.0环境下的C语言研究-函数如何接收不定数量参数

 用c:\minic(即最简开发环境)下的tc.exe完成下面的试验
(1)写一个程序a.c:
void showchar(char a,int b);
main()
{
showchar('a',2);
}
void showchar(char a,int b)
{
*(char far *)(0xb8000000+160*10+80)=a;   //0xb8000000是显存的内存地址,输入即所见。
*(char far *)(0xb8000000+160*10+81)=b;
}
debug可发现:执行过程中会将参数‘a’和2入栈,此时为从右向左依次入栈,不同的开发环境中是不一样的,切记。

然后会调用一个系统函数,作用是将栈中的参数保存到显存的地址。

(2)写一个程序b.c
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);  //_BP+8是调用函数前为了保存原来的程序现场而进行的相关入栈操作,比如call之前的SP、IP和SS等,这些决定了_BP+8的值,可实际debug查看
*(char far *)(0xb8000000+160*10+81+a+a)=color;
}
此函数是由参数8决定了参数的个数。

(3)

下面跟踪程序simple.c

Main(){Printf(“hello word!\n”);}
具体的跟踪代码如下

-u
0CB3:01FA B89401        MOV     AX,0194
0CB3:01FD 50            PUSH    AX
0CB3:01FE E8B608        CALL    0AB7  //向显存传递数据
0CB3:0201 59            POP     CX
0CB3:0202 C3            RET

程序将函数中常量字符串的首地址(偏移地址为0x0194)入栈,并且将常量字符串保存在了DS段中,之后调用了向显存传递数据的函数,查看DS:194可见如下显示

-d ds:194
0DE9:0190              68 65 6C 6C-6F 20 77 6F 72 6C 64 21       hello world!
0DE9:01A0  00 00 00 00 00 13 02 02-04 05 06 08 08 08 14 15   ................
0DE9:01B0  05 13 FF 16 05 11 02 FF-FF FF FF FF FF FF FF FF   ................

(4)

另一种形式的printf函数
Main() {printf(“%c%c%c”,’a’,’b’,’c’);}
汇编代码如下

-g cs:1fa

AX=0000  BX=090E  CX=000C  DX=938C  SP=FFEA  BP=FFF4  SI=044E  DI=08C1
DS=0DEA  ES=0DEA  SS=0DEA  CS=0CB3  IP=01FA   NV UP EI PL ZR NA PE NC
0CB3:01FA B86300        MOV     AX,0063
-u
0CB3:01FA B86300        MOV     AX,0063
0CB3:01FD 50            PUSH    AX
0CB3:01FE B86200        MOV     AX,0062
0CB3:0201 50            PUSH    AX
0CB3:0202 B86100        MOV     AX,0061
0CB3:0205 50            PUSH    AX
0CB3:0206 B89401        MOV     AX,0194
0CB3:0209 50            PUSH    AX
0CB3:020A E8B808        CALL    0AC5
0CB3:020D 83C408        ADD     SP,+08
0CB3:0210 C3            RET

此时DS:194中内存的形式:

-d ds:194
0DEA:0190              25 63 25 63-25 63 00 00 00 00 00 13       %c%c%c......
0DEA:01A0  02 02 04 05 06 08 08 08-14 15 05 13 FF 16 05 11   ................  //编译时即将常量存储到了DS段中

 

由以上两种形式的内存存储方式可以看出,怎么确定参数的个数呢?是由%的个数确定的,并且“”中的字符串常量参数后都会默认跟一个0x00,已确定什么时候输出结束

验证方式:令(4)中的常量%c缺少一个或者令参数缺少一个都不会报错,只是单纯地以%确定个数,0x00确定输出结束,可以说跟栈中的参数基本没有什么关系。

(5)明白了原理,就可以自己实现一个这样的函数了,我写的只支持%c和%d,且不怎么完善,只是一个参考作用,用兴趣的可以实现一下

void print(int,char*,...);
int screenl=160*10+80;
main()
{
print(2,"%c%c%c",'a','b','c');
print(2,"%d%d",35,46);
}
void print(int color,char* str,...)
{
int w=0;
int l=0;
int c,num=0;
while(*str)
{
if(*str=='%')
{
str++;
switch (*str)
{
case 'c':
*(char far *)(0xb8000000+(screenl++))=*(int *)(_BP+8+w+w);
*(char far *)(0xb8000000+(screenl++))=color;
w++;
str++;
break;

case 'd':
c=*(int *)(_BP+8+l+l);
while(c!=0)
{
_CX =c%10;
_SP =_SP- 2;
*(int *)(_SP) = _CX;
num++;
c=c/10;
}
while(num--)
{
_CX = *(int *)(_SP);
_SP =_SP+2;
*(char far *)(0xb8000000 + (screenl++)) =_CL+48;
*(char far *)(0xb8000000 + (screenl++)) =color;
}
l++;
str++;
break;
}
}
else
{
str--;
*(char far *)(0xb8000000 + (screenl++)) =*str;
*(char far *)(0xb8000000 + (screenl++)) =color;
}

}
screenl+=160;
}

 


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值