一个printf实现 [英] a printf implementation

查看:70
本文介绍了一个printf实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写过这个函数,并且想知道是否有其他人可以指出,如果它有任何问题,请指出
。目的是在某种情况下,无论出于何种原因必须使用低级别[超出此新闻组的范围]的I / O,

替代printf,并且

内存分配不能用于[因为它失败的风险或其他什么

其他] - 主要是它对我来说是一个练习口译

类似printf的格式字符串,我想我会在这里发布,看看是否

任何人都可以指出它中的任何错误 - 即任何会导致
$ b的东西$ b未定义的行为,以及它可能无法解决的任何有效格式字符串

解释[它没有实现的功能,但它应该在

最不流行关闭任何给定的有效格式字符串的所有相同的参数

一个真正的printf函数将会出现。]


[这是适合这类事情的新闻组?]

______


#include< limits.h>

#include< stdarg.h>

#include< ; stddef.h>

#include< stdint.h>

#include< stdio.h>

#include< stdlib .h>

#include< string.h>

#include< time.h>

#include< wchar.h> ;


int write(int fd,char * buf,size_t len);


#if 0 / *如果你的系统没有'' t具有这个特定于平台的功能* /

静态FILE * fdtab [] = {stdin,stdout,stderr,0,0,0,0,0,0,0};

int write(int fd,char * buf,size_t len){

if(fd> 0 || !fdtab [fd]){

返回-1;

}

返回fwrite(buf,1,len,fdtab [fd]) ;

}

#endif


#define LENGTH 64


静态字符buf [LENGTH];

static int pos;

static char const udigit [16] =" 0123456789ABCDEF" ;;

static char const ldigit [16] =" 0123456789abcdef";

static const char * digits;


static void flush(int fd){

写(fd,buf,pos);

pos = 0;

}


static inline void eputc(int fd ,int c){

buf [pos ++] = c;

if(pos == LENGTH)flush(fd);

}


静态内联void eputwc(int fd,wint_t c){

int x = wctob(c); eputc(fd,x< 0?''?'':x);

}


static void eputws(int fd,wchar_t * s){

while(* s){eputwc(fd,* s);小号++; }

}


static void eputs(int fd,char * s){

while(* s){eputc( FD,* S);小号++; }

}


静态字符* uimaxtoa(uintmax_t n,int base){

static char buf [CHAR_BIT * sizeof( n)+2];

char * endptr = buf +(sizeof buf)-2;

do {

* endptr - = digits [n%base];

n / = base;

} while(n);

返回endptr + 1;

}


静态字符* pcvt(void * p){

静态字符buf [sizeof(void *)* CHAR_BIT];

/ *好吧,我们总是希望这适合 - 任何人都知道更多

*便携式方式来实现%p? * /

sprintf(buf,"%p",p);

返回buf;

}

静态字符* tcvt(time_t t){

static char buf [] =" YYYY-MM-DD HH:MM:SS" ;;

strftime(buf,sizeof buf,%Y-%m-%d%H:%M:%S,gmtime(& t));

返回buf;

}


void eprintf(int fd,const char * fmt,...){

int c;

va_list ap;

int islong = 0;

uintmax_t uarg;

intmax_t iarg;


va_start(ap,fmt);


循环:

for(; * fmt&& * fmt!=''%''; fmt ++ )

eputc(fd,* fmt);

if(!* fmt)goto end;

if(* fmt ++ =='' %''){

islong = 0;

digits = ldigit;

top:

c = * fmt ++ ;

重试:

开关(c){

case''c'':

if(islong )eputwc(fd,va_arg(ap,wint_t));

else eputc(fd,va_arg(ap,int));

break;

/ * obsole te,但它与任何事物都没有冲突。 * /

案例''D'':案例''O'':案例''U'':案例''C'':案例''S'':

islong = 1; C = tolower的(C); goto retry;

case''A'':case''E'':case'''F''case'''G'':case'''X'':

digits = udigit; c = tolower(c); goto retry;

case''d'':case''i'':

switch(islong){

case 0:iarg va_arg函数=(AP,int);在休息;

案例1:iarg = va_arg(ap,long int);休息;

案例2:iarg = va_arg(ap,long long int);打破;

//这在非二重补充系统上是错误的

情况3:iarg = va_arg(ap,size_t);休息;

案例4:iarg = va_arg(ap,ptrdiff_t);休息;

案例5:iarg = va_arg(ap,intmax_t);休息;

}

if(iarg< 0){

eputc(fd,'' - '');

uarg = -iarg;

}否则{

uarg = iarg;

}

goto cvt ;

case''o'':case''u'':case''x'':

switch(islong){

case 0:uarg = va_arg(ap,unsigned);休息;

案例1:uarg = va_arg(ap,long unsigned);休息;

案例2:uarg = va_arg(ap,long long unsigned);休息;

案例3:uarg = va_arg(ap,size_t);打破;

//这在非二元补充系统上是错误的。

案例4:uarg = va_arg(ap,ptrdiff_t);休息;

案例5:uarg = va_arg(ap,uintmax_t);休息;

}

cvt:

eputs(fd,uimaxtoa(uarg,c ==''o''?8:(c ==''x''?16:10)));

休息;

case''p'':

eputs( FD,pcvt(在va_arg(AP,无效*)));休息;

案例's'':

if(islong)eputws(fd,va_arg(ap,wchar_t *));

else eputs(fd,va_arg(ap,char *));

break;

/ *我自己的扩展,他们打印一个表示errno值的int和

*分别为time_t。 %!调用strerror()。 * /

case''!'':

eputs(fd,strerror(va_arg(ap,int)));休息;

案例''T'':

eputs(fd,tcvt(va_arg(ap,time_t)));休息;

案例0:

转到结尾;

默认:

eputs(fd,"%? "); / * fall * /

case''%'':

write(fd,& c,1);休息;

case''l'':islong ++; if(islong> 2)islong = 2;转到顶部;

案例''j'':islong = 5;转到顶部;

case''t'':islong = 4;转到顶部;

case''z'':islong = 3;转到顶部;

//这里'我们没有实现的东西

case''n'':

switch( islong){

案例0 :(无效)va_arg(ap,int *);休息;

案例1 :(无效)va_arg(ap,long *);休息;

案例2 :(无效)va_arg(ap,long long *);休息;

案例3 :(无效)va_arg(ap,size_t *);打破;

//这在非二元补充系统上是错误的。

案例4 :(无效)va_arg(ap,ptrdiff_t *);休息;

案例5 :(无效)va_arg(ap,intmax_t *);休息;

}休息;

case''*'':

(无效)va_arg(ap,int);

case''0'':case''''':case''2'':case''3'':case''4'':

case'' 5'':case''6'':case''7'':case''8'':case'''9'':

case''。'':case'' #'':case''+'':case'' - '':case'''':

case''\'''':

转到顶部;

案例''$'':

/ *这个,我甚至不能假装支持 - 呃,好吧,这是posix的事情,

*而不是C的东西,无论如何。 * /

eputs(fd,"%$ ????? \ n");

flush(fd);

返回;

/ *我现在不想乱搞浮点数* /

case''L'':

islong = 2; goto top;

case''a'':case''e'':case''f'':case''g'':

if(islong == 2)(void)va_arg(ap,long double);

else if(islong == 2)(void)va_arg(ap,double);

eputs (fd,%FLT?);

休息;

}

}

转到循环;

结束:

flush(fd);

}

I have written this function and was wondering if anyone else could
point out if there''s anything wrong with it. The purpose is to
substitute for printf when in a situation where low-level [beyond the
scope of this newsgroup] I/O has to be used for whatever reason, and
memory allocation cannot be used [for risk of it failing or whatever
else] - mainly it''s become for me an exercise in interpreting
printf-like format strings, and i thought i''d post it here to see if
anyone can point out any bugs in it - i.e. anything that would cause
undefined behavior, and any valid format strings it might fail to
interpret [there''s functionality it doesn''t implement, but it should at
least pop off all the same arguments for any given valid format string
that a real printf function will.]

[is this the appropriate newsgroup for this kind of thing?]
______

#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <wchar.h>

int write(int fd,char*buf,size_t len);

#if 0 /*if your system doesn''t have this platform-specific function*/
static FILE * fdtab[] = { stdin, stdout, stderr, 0, 0, 0, 0, 0, 0, 0 };
int write(int fd,char *buf,size_t len) {
if(fd > 0 || !fdtab[fd]) {
return -1;
}
return fwrite(buf,1,len,fdtab[fd]);
}
#endif

#define LENGTH 64

static char buf[LENGTH];
static int pos;
static char const udigit[16] = "0123456789ABCDEF";
static char const ldigit[16] = "0123456789abcdef";
static const char *digits;

static void flush(int fd) {
write(fd,buf,pos);
pos=0;
}

static inline void eputc(int fd, int c) {
buf[pos++]=c;
if(pos==LENGTH) flush(fd);
}

static inline void eputwc(int fd, wint_t c) {
int x = wctob(c); eputc(fd,x<0?''?'':x);
}

static void eputws(int fd, wchar_t *s) {
while(*s) { eputwc(fd,*s); s++; }
}

static void eputs(int fd, char *s) {
while(*s) { eputc(fd,*s); s++; }
}

static char * uimaxtoa(uintmax_t n, int base) {
static char buf[CHAR_BIT*sizeof(n)+2];
char *endptr=buf+(sizeof buf)-2;
do {
*endptr--=digits[n%base];
n/=base;
} while(n);
return endptr+1;
}

static char * pcvt(void *p) {
static char buf[sizeof(void *)*CHAR_BIT];
/* well, we can always hope this will fit - anyone know a more
* portable way to implement %p? */
sprintf(buf,"%p",p);
return buf;
}

static char * tcvt(time_t t) {
static char buf[] = "YYYY-MM-DD HH:MM:SS";
strftime(buf,sizeof buf,"%Y-%m-%d %H:%M:%S",gmtime(&t));
return buf;
}

void eprintf(int fd, const char *fmt, ...) {
int c;
va_list ap;
int islong=0;
uintmax_t uarg;
intmax_t iarg;

va_start(ap,fmt);

loop:
for(;*fmt&&*fmt!=''%'';fmt++)
eputc(fd,*fmt);
if(!*fmt) goto end;
if(*fmt++ == ''%'') {
islong=0;
digits=ldigit;
top:
c = *fmt++;
retry:
switch(c) {
case ''c'':
if(islong) eputwc(fd,va_arg(ap,wint_t));
else eputc(fd,va_arg(ap,int));
break;
/* obsolete, but it doesn''t conflict with anything. */
case ''D'': case ''O'': case ''U'': case ''C'': case ''S'':
islong=1; c=tolower(c); goto retry;
case ''A'': case ''E'': case ''F'': case ''G'': case ''X'':
digits=udigit; c = tolower(c); goto retry;
case ''d'': case ''i'':
switch(islong) {
case 0: iarg=va_arg(ap,int); break;
case 1: iarg=va_arg(ap,long int); break;
case 2: iarg=va_arg(ap,long long int); break;
// this is wrong on non-twos-complement systems
case 3: iarg=va_arg(ap,size_t); break;
case 4: iarg=va_arg(ap,ptrdiff_t); break;
case 5: iarg=va_arg(ap,intmax_t); break;
}
if(iarg<0) {
eputc(fd,''-'');
uarg=-iarg;
} else {
uarg=iarg;
}
goto cvt;
case ''o'': case ''u'': case ''x'':
switch(islong) {
case 0: uarg=va_arg(ap,unsigned); break;
case 1: uarg=va_arg(ap,long unsigned); break;
case 2: uarg=va_arg(ap,long long unsigned); break;
case 3: uarg=va_arg(ap,size_t); break;
// this is wrong on non-twos-complement systems.
case 4: uarg=va_arg(ap,ptrdiff_t); break;
case 5: uarg=va_arg(ap,uintmax_t); break;
}
cvt:
eputs(fd,uimaxtoa(uarg,c==''o''?8:(c==''x''?16:10)));
break;
case ''p'':
eputs(fd,pcvt(va_arg(ap,void*))); break;
case ''s'':
if(islong)eputws(fd,va_arg(ap,wchar_t *));
else eputs(fd,va_arg(ap,char *));
break;
/* my own extensions, they print an int representing an errno value and
* a time_t, respectively. %! calls strerror(). */
case ''!'':
eputs(fd,strerror(va_arg(ap,int))); break;
case ''T'':
eputs(fd,tcvt(va_arg(ap,time_t))); break;
case 0:
goto end;
default:
eputs(fd,"%?"); /*fall*/
case ''%'':
write(fd,&c,1); break;
case ''l'': islong++; if(islong > 2) islong=2; goto top;
case ''j'': islong=5; goto top;
case ''t'': islong=4; goto top;
case ''z'': islong=3; goto top;
// here''s the stuff we don''t implement
case ''n'':
switch(islong) {
case 0: (void)va_arg(ap,int *); break;
case 1: (void)va_arg(ap,long *); break;
case 2: (void)va_arg(ap,long long *); break;
case 3: (void)va_arg(ap,size_t *); break;
// this is wrong on non-twos-complement systems.
case 4: (void)va_arg(ap,ptrdiff_t *); break;
case 5: (void)va_arg(ap,intmax_t *); break;
} break;
case ''*'':
(void)va_arg(ap,int);
case ''0'': case ''1'': case ''2'': case ''3'': case ''4'':
case ''5'': case ''6'': case ''7'': case ''8'': case ''9'':
case ''.'': case ''#'': case ''+'': case ''-'': case '' '':
case ''\'''':
goto top;
case ''$'':
/* this, i can''t even pretend to support - eh, well, it''s a posix thing,
* rather than a C thing, anyway. */
eputs(fd,"%$?????\n");
flush(fd);
return;
/* I don''t feel like messing with floating point right now */
case ''L'':
islong=2; goto top;
case ''a'': case ''e'': case ''f'': case ''g'':
if(islong == 2) (void)va_arg(ap, long double);
else if(islong == 2) (void)va_arg(ap, double);
eputs(fd,"%FLT?");
break;
}
}
goto loop;
end:
flush(fd);
}

推荐答案

'':

/ *这个,我甚至不能假装支持 - 呃,好吧,这是posix的东西,

*而不是无论如何,不​​是C事。 * /

eputs(fd,"%
'':
/* this, i can''t even pretend to support - eh, well, it''s a posix thing,
* rather than a C thing, anyway. */
eputs(fd,"%


????? \ n");

flush(fd) );

返回;

/ *我现在不想搞乱浮点* /

case''L' ':

islong = 2; goto top;

case''a'':case''e'':case''f'':case''g'':

if(islong == 2)(void)va_arg(ap,long double);

else if(islong == 2)(void)va_arg(ap,double);

eputs (fd,%FLT?);

休息;

}

}

转到循环;

结束:

flush(fd);

}
?????\n");
flush(fd);
return;
/* I don''t feel like messing with floating point right now */
case ''L'':
islong=2; goto top;
case ''a'': case ''e'': case ''f'': case ''g'':
if(islong == 2) (void)va_arg(ap, long double);
else if(islong == 2) (void)va_arg(ap, double);
eputs(fd,"%FLT?");
break;
}
}
goto loop;
end:
flush(fd);
}


Jordan Abel写道:
Jordan Abel wrote:
va_start(ap,fmt);
va_start(ap,fmt);




应该有一个

va_end(ap);

某处。


-

pete



There should probably be a
va_end(ap);
somewhere.

--
pete


这篇关于一个printf实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆