一直好奇c语言中int printf( const char* format, …) 可变参数函数是怎样实现的,网上关于可变参数函数的实现基本上使用了va_list,va_start,va_end等内置宏定义,为了更深入的理解可变参数函数,决定直接使用内置汇编来实现关键操作。
1.可变参数函数的形参使用(…)来表示可变个数的参数,在实际调用时,所有的参数都会被压入栈中,需要自行从栈中读取参数,这只能使用内置汇编来实现了。关键汇编代码如下:
asm("pushl %%ebp;addl %1,%%ebp;movl (%%ebp),%%eax;popl %%ebp;":"=a"(v):"m"(offset));
my_printf.c
#include <stdio.h>
#define is_digit(c) ((c) >= '0' && (c) <= '9')
//#define NULL ((void *) 0)
static int my_atoi(const char *s)
{
int i=0;
while (is_digit(*s))
i = i*10 + *(s++) - '0';
return i;
}
static int my_itoa(const int v,char *s)
{
int yi=0,result=0,a=v;
char c[11];
if(a==0){
s[0]='0',s[1]='\0';
return 1;
}
while(a!=0){
yi=a%10;
a=a/10;
result++;
c[result]=(char)(yi+48);
}
s[result]='\0';
int i=0;
for(i=result;i>0;i--)s[result-i]=c[i];
return result;
}
static int my_itox(const int v,char *s){
int yi=0,result=0,value=v;
char c[8]={'0','0','0','0','0','0','0','0'};
if(value!=0){
while(value!=0){
yi=value%16;
if(yi>9){
yi=yi-9;
c[result]=(char)(yi+64);
}else{
c[result]=(char)(yi+48);
}
value=value/16;
result++;
}
}else{
s[0]='0',s[1]='\0';
return 1;
}
c[result]='\0';
s[result]='\0';
int i=0;
for(i=result;i>0;i--)s[result-i]=c[i-1];
return result;
}
int my_strcpy(char *des,char *src,int skip){
int i=0;
char *p=src;
while(*p!='\0'){
des[skip+(i++)]=*(p++);
}
return i;
}
static int my_strlen(const char *s)
{
int i=0;
while(*(s++)!='\0')i++;
return i;
}
static int my_printf(const char *fmt, ...)
{
int num=1;
int buf_index=0;
char buf[1024]={'0'};//存储将打印到屏幕的字符串
char* p=fmt;
while(*p!='\0'){
buf[buf_index++]=*p;
if(*p=='%'){
buf_index--;
p++;
switch (*p){
case 'd':{
int v=0;
char a[10];
int offset=num*4+8;
asm("pushl %%ebp;addl %1,%%ebp;movl (%%ebp),%%eax;popl %%ebp;":"=a"(v):"m"(offset));
int len=my_itoa(v,a);
my_strcpy(buf,a,buf_index);
buf_index=buf_index+len;
break;
}
case 'c':{
int v=0;
int offset=num*4+8;
asm("pushl %%ebp;addl %1,%%ebp;movl (%%ebp),%%eax;popl %%ebp;":"=a"(v):"m"(offset));
buf[buf_index]=(char)v;
buf_index=buf_index+1;
break;
}
case 's':{
char* v=NULL;
int offset=num*4+8;
asm("pushl %%ebp;addl %1,%%ebp;movl (%%ebp),%%eax;popl %%ebp;":"=a"(v):"m"(offset));
int vlen=my_strcpy(buf,v,buf_index);
buf_index=buf_index+vlen;
break;
}
case 'x':{
int v=0;
char a[10];
int offset=num*4+8;
asm("pushl %%ebp;addl %1,%%ebp;movl (%%ebp),%%eax;popl %%ebp;":"=a"(v):"m"(offset));
int len=my_itox(v,a);
my_strcpy(buf,a,buf_index);
buf_index=buf_index+len;
break;
}
default:
break;
}//switch
num++;//²ÎÊý¸öÊý
}//if
p++;
}//while
buf[buf_index]='\0';
printf("\n%s",buf);
return buf_index;
}
int main(){
my_printf("a=%d,b=%x,d=%c,s=%s",322343,0xabcd,'A',"hello\n");
return 0;
}