根据综合研究5的showchar()函数,可以了解参数都是由栈传递的,所要传递参数的个数也可以由栈传递。那么printf函数要输出的参数肯定也是由栈传递。另外一点就是printf函数肯定有某种信息,这种信息记录了需要打印的个数。
main()
{
printf("%c,%d/n",'a',2);
}
函数如上,编译连接后用反汇编查看cs:01fa
能看出来,打印的参数‘a’,2都是由栈传递。入栈的时候还有一个未知信息:mov ax,0194
Push ax
0194肯定不是我们需要打印的参数,那么它就是printf函数自己添加的。根据上面的假设,printf自己能够获取信息,得知所要打印参数的个数。这个信息应该也放在内存的某个位置。那么会不会0194就是那个位置的IP?
查看一下:
在数据段的ip=0194位置处,存放了这些信息。可以肯定printf函数就是从这个位置得到信息,确定当前要打印的参数类型的。
再修改一下main函数,查看一下:
main()
{
printf("%c,%d,%s,%c/n",'a',2,"hello",'d');
}
倒数第二个打印参数是个字符串,入栈的01a1应该是字符串的首地址。查看一下ds:0194
Ds:01a1正好是“hello“的地址。这样我们能够得知:
printf("%c,%d,%s,%c/n",'a',2,"hello",'d'); printf();里面有字符串“%C,%d,%s,%c/n”,“hello”,还有char型‘a’,‘d’,int型2. 这里面的int型和char型数据被放到栈里,字符串型数据放在了DS:0194位置处。并且DS:0194处,字符串以0结束。
自己写printf函数。想法:
打印位置:
dh=行,dl=列。
(1) 以printf("%c,%d,%s,%c/n",'a',2,"hello",'d')为例。
从 "%c,%d,%s,%c/n"里找要打印的信息属性。这个字符串的长度也能求出来。(0AH是‘/n’的ASICⅡ)
(2)检测"%c,%d,%s,%c/n",如果当前是%C则打印出字符,是%D打印int型数据,是%S则打印字符串。是‘/n’,行号加1
如果是int数据,如234,要用逐位摸除方法,转换程字符‘2’,‘3’,‘4’再打印。因为显存上显示的都是字符型。
(3)检测到非上述信息,直接打印。
程序如下:
void print(char *,...);main(){ clrscr(); printf("%d,%c",123,'x'); print("%c,ccc%s,%d/n%d,%c",'a',"hello",1123,5,'d');
}void print(char *p,...){
int count=0; /* the station of int and char used in stack */ int data=0; int signal=0;
char *buffer=(char *)malloc(10); char *str=0; int dh=10; int dl=0;
while(*p!=0) {
if(*p=='%' && *(p+1)=='c') { *(char far *)(0xb8000000+160*dh+2*dl)=*(int *)(_BP+6+count+count); count++; dl=dl+1; p+=2; } else if(*p=='%' && *(p+1)=='d') { data=*(int *)(_BP+6+count+count) ; count++; p+=2; if(data==0){ *(char far *)(0xb8000000+160*dh+2*dl)=0x30; dl+=1;} if(data<0) { signal=1; data=-data; } buffer[0]=0; while(data!=0) { buffer++; *buffer=data+0x30; data=data/10; } while(*buffer!=0) { if(signal==1) { *(char far *)(0xb8000000+160*dh+2*dl)='-'; dl++; signal=0; } *(char far *)(0xb8000000+160*dh+2*dl)=*buffer; buffer--; dl++; }
} else if(*p=='%' && *(p+1)=='s') {/*这里进行一个类型转化,把从栈里取得的int型数据,转换为char型指针*/
str=(char *)*(int *)(_BP+6+count+count);
count++; while(*str!=0) { *(char far *)(0xb8000000+160*dh+2*dl)=*str; str++; dl++; } p+=2;
} else if(*p=='/n') { dh++; dl=0; p++; }
else { *(char far *)(0xb8000000+160*dh+2*dl)=*p; dl++; p++; }
}}