支持格式化duxXcspo,并支持控制符+-.0这溅,有測試代碼
人狠話不多啤它,直接上完整代碼。
#include <stdint.h>
#include <stdarg.h>
#define FORMAT_ALIGN_RIGHT 0 //默認(rèn)右對齊
#define FORMAT_ALIGN_LEFT 1 //左對齊 '-'
#define FORMAT_SIGN_FLAG 2 //強制正負數(shù)符號 '+'
#define FORMAT_PADDING_ZERO 4 //填充0代替空格 '0'
static int print(char **out, int ch)
{
int count = 1;
if (ch == '\n')
count += print(out, '\r');
if (out)
*(*out)++ = ch;
else
putchar(ch);
return count;
}
static int prints(char **out, const char *str, int flags, int minW, int maxW)
{
int pad = flags & FORMAT_PADDING_ZERO ? '0' : ' ';
int len = 0, padLen = 0;
const char *ptr;
int ret = 0;
//字符串長度
for (ptr = str; *ptr; ++ptr)
len++;
//max修正
if (maxW < minW)
maxW = minW;
if (len < minW)
{
//需要填充
padLen = minW - len;
}
//需要填充 pad 字符
if (!(flags & FORMAT_ALIGN_LEFT))
{
//不是左對齊岛啸,先填充
for (; padLen > 0; padLen--)
{
ret += print(out, pad);
}
}
//輸出字符串
while (*str)
{
if (maxW && ret == maxW)
{
//字符串已達規(guī)定最大長度
break;
}
ret += print(out, *str++);
}
//如果是左對齊,那么 padLen 應(yīng)該是非0
for (; padLen > 0; padLen--)
{
ret += print(out, pad);
}
return ret;
}
static int printi(char **out, int val, int sign, int base, int alphaBase, int flags, int minW, int maxW)
{
unsigned int uval = (unsigned int)val;
char buf[32], *ptr;
int neg = 0, len = 0;
int forceSign = flags & FORMAT_SIGN_FLAG;
int padZero = flags & FORMAT_PADDING_ZERO;
if (sign)
{
if (val < 0)
{
neg = 1;
uval = (unsigned int)-val;
}
}
ptr = buf + sizeof(buf) - 1;
*ptr = '\0';
while (uval)
{
int t = uval % base;
if (t >= 10)
t += alphaBase - '0' - 10;
*--ptr = t + '0';
uval /= base;
len++;
}
if (forceSign || neg)
len++;
if (padZero && len < minW)
{
int padLen = minW - len;
int padMax = sizeof(buf) - len - 1;
if (padLen > padMax)
padLen = padMax;
while (padLen--)
*--ptr = '0';
}
if (neg)
*--ptr = '-';
else if (forceSign)
*--ptr = '+';
return prints(out, ptr, flags, minW, maxW);
}
static int vprintf_internal(char *buf, const char *fmt, va_list va)
{
char *dst = buf;
char **out = buf ? &dst : NULL;
int count = 0;
while (*fmt)
{
if (*fmt == '%')
{
int flags = 0, minW = 0, maxW = 0;
int type, waitMin = 0, waitMax = 0;
char *str, tmp[2];
fmt++;
while (1)
{
type = *fmt++;
if (!type)
break;
switch (type)
{
case '%':
goto _out;
case '-':
flags |= FORMAT_ALIGN_LEFT;
break;
case '+':
flags |= FORMAT_SIGN_FLAG;
break;
case '.':
waitMax = 1;
break;
case '0':
if (!waitMin && !waitMax)
{
flags |= FORMAT_PADDING_ZERO;
waitMin = 1;
}
else
{
goto _num;
}
break;
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
_num:
if (!waitMin && !waitMax)
{
waitMin = 1;
}
if (waitMin)
{
minW = minW * 10 + type - '0';
}
else if(waitMax)
{
maxW = maxW * 10 + type - '0';
}
break;
case 'd': case 'u': case 'x': case 'X':
case 'c': case 's': case 'p': case 'o':
goto _format;
default:
goto _out;
}
}
_format:
switch (type)
{
case 'o':
count += printi(out, va_arg(va, int), 0, 8, 'A', flags, minW, maxW);
break;
case 'd':
count += printi(out, va_arg(va, int), 1, 10, 'A', flags, minW, maxW);
break;
case 'u':
count += printi(out, va_arg(va, int), 0, 10, 'A', flags, minW, maxW);
break;
case 'x':
count += printi(out, va_arg(va, int), 0, 16, 'a', flags, minW, maxW);
break;
case 'X':
count += printi(out, va_arg(va, int), 0, 16, 'A', flags, minW, maxW);
break;
case 'c':
tmp[0] = (char)va_arg(va, int);
tmp[1] = 0;
count += prints(out, tmp, flags, minW, maxW);
break;
case 's':
str = va_arg(va, char *);
str = str ? str : "(null)";
count += prints(out, str, flags, minW, maxW);
break;
case 'p':
count += prints(out, "0x", 0, 0, 0);
count += printi(out, va_arg(va, int), 0, 16, 'A', FORMAT_PADDING_ZERO, 8, 0);
break;
}
continue;
}
else
{
_out:
count += print(out, *fmt);
}
fmt++;
}
if (out)
**out = '\0';
va_end(va);
return count;
}
int printf(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
return vprintf_internal(0, fmt, va);
}
int vsprintf(char *buf, const char *fmt, va_list va)
{
return vprintf_internal(buf, fmt, va);
}
int sprintf(char *buf, const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
return vprintf_internal(buf, fmt, va);
}
void ShowBinary(void *buf, int len)
{
int i = 0;
unsigned char *p = (unsigned char *)buf;
while (len)
{
i++;
printf("%02X ", (int)p[0]);
if ((i % 16) == 0)
printf("\n");
p++;
len--;
}
printf("\n");
}
int main(int argc, char *argv[])
{
printf("a=[%s]\n", "0123456789");
printf("a=[%12s]\n", "0123456789");
printf("a=[%-12s]\n", "0123456789");
printf("a=[%.12s]\n\n", "01234567890123456789");
printf("a=[%d]\n", 0xFFFFFFFF);
printf("a=[%u]\n", 0xFFFFFFFF);
printf("a=[%+u]\n\n", 0xFFFFFFFF);
printf("a=[%15d]\n", 0xFFFFFFFF);
printf("a=[%-15d]\n", 0xFFFFFFFF);
printf("a=[%+-15d]\n", 0xFFFFFFFF);
printf("a=[%015d]\n", 0xFFFFFFFF);
printf("a=[%-015d]\n", 0xFFFFFFFF);
printf("a=[%+-015d]\n\n", 0xFFFFFFFF);
printf("a=[%15u]\n", 0xFFFFFFFF);
printf("a=[%-15u]\n", 0xFFFFFFFF);
printf("a=[%+-15u]\n", 0xFFFFFFFF);
printf("a=[%015u]\n", 0xFFFFFFFF);
printf("a=[%-015u]\n", 0xFFFFFFFF);
printf("a=[%+-015u]\n\n", 0xFFFFFFFF);
printf("a=[%15x]\n", 0xFFFFFFFF);
printf("a=[%-15x]\n", 0xFFFFFFFF);
printf("a=[%+-15x]\n", 0xFFFFFFFF);
printf("a=[%015x]\n", 0xFFFFFFFF);
printf("a=[%-015x]\n", 0xFFFFFFFF);
printf("a=[%+-015x]\n\n", 0xFFFFFFFF);
printf("a=[%15X]\n", 0xFFFFFFFF);
printf("a=[%-15X]\n", 0xFFFFFFFF);
printf("a=[%+-15X]\n", 0xFFFFFFFF);
printf("a=[%015X]\n", 0xFFFFFFFF);
printf("a=[%-015X]\n", 0xFFFFFFFF);
printf("a=[%+-015X]\n\n", 0xFFFFFFFF);
printf("a=[%15o]\n", 0xFFFFFFFF);
printf("a=[%-15o]\n", 0xFFFFFFFF);
printf("a=[%+-15o]\n", 0xFFFFFFFF);
printf("a=[%015o]\n", 0xFFFFFFFF);
printf("a=[%-015o]\n", 0xFFFFFFFF);
printf("a=[%+-015o]\n\n", 0xFFFFFFFF);
getch();
return 0;
}