您的位置:首页 > 编程语言 > C语言/C++

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

2011-09-24 12:46 387 查看
用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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: