系統(tǒng)調(diào)試信息的顯示方法
表2 函數(shù)調(diào)用時(shí)的參數(shù)在堆棧中的存儲(chǔ)情況(X86環(huán)境)
表2說明了兩個(gè)問題:第一個(gè)問題是,每個(gè)參數(shù)在堆棧中的存儲(chǔ)長度和參數(shù)的類型有關(guān)。對(duì)于指針類型參數(shù),參數(shù)長度和編譯模式有關(guān):大模式下,地址包括段地址和偏移地址,共4字節(jié);而小模式下,地址只有段內(nèi)偏移,占2字節(jié)。第二個(gè)問題是,如果知道其中的一個(gè)參數(shù)地址和參數(shù)的類型,則可以得到任意參數(shù)的數(shù)值,并不需要知道參數(shù)的名稱。比如在函數(shù)fun()中,可用以下代碼顯示各個(gè)參數(shù)的內(nèi)容:
void fun(char *str,int i,float *a)
{
void *p
p=str;
printf(str=%s,str); p=(char **)p+1;
printf(i=%d ((int*)p));p=(int *)p+1;
printf(i=%d *((float *)p));
}
3 PC機(jī)上的printf()函數(shù)的設(shè)計(jì)實(shí)現(xiàn)
現(xiàn)在,可以編寫自己的printf()函數(shù)了。以下給出TC20編譯環(huán)境下的具體實(shí)現(xiàn)代碼,在其他環(huán)境下,可以根據(jù)該原理進(jìn)行移植。也可以按位顯示二進(jìn)制數(shù)。對(duì)于其他類型,讀者可以根據(jù)需要增刪。
在實(shí)際應(yīng)用中,可以修改其中的putchar()函數(shù),將字符發(fā)到串口,就可以達(dá)到上述目的了。這里我們編寫的函數(shù)還增加了數(shù)字的二進(jìn)制顯示,這對(duì)于很多位域應(yīng)用是很有用處的。
/*printf()函數(shù)的實(shí)現(xiàn)代碼,為和庫函數(shù)區(qū)別,特在各函數(shù)前增加前綴“my”*/
void myprintf(char *fmt,…)
{
void *p;
char ch;
p=fmt;p=(char**)p+1;/*指向堆棧中的下一個(gè)參數(shù)*/
while(1){
while((ch=*fmt++)!='%'{/*讀入格式字符串*/
if(ch= ='0')return;
putchar(ch);
};
ch=*fmt++;
switch(ch){ /*格式字符分析*/
/*因?yàn)樽址麉?shù)傳遞時(shí)也轉(zhuǎn)換成整形參數(shù)傳遞,故同樣處理*/
case 'c':
case'd':
case'x':
case'0':
case'b':
if(ch= ='c')myputchar(*(int *)p));
if(ch= ='d')myprintn(*((int *)p),10);
if(ch= ='x')myprintn(*((int *)p),16);
if(ch= ='o')myprintn(*((int *)p),8);
if(ch= ='b')myprintn(*((int *)p),2);
p=(int)p+1; /*指針移動(dòng)*/
break;
case's':
myputs(*((char **)p));
p=(char **)p+1; /*指針移動(dòng)*/
break;
default;
};
}
}
評(píng)論