实现c/c++的printf函数

194 阅读2分钟

本文已参与「新人创作礼」活动.一起开启掘金创作之路。

随着对printf函数的深入理解后,发现,网上许多版本的实现都无法针对大整数和负数做很好的处理,而这个版本针对了负数以及最大的整数和最小的整数都能正常输出。

#include <stdio.h>
#include <stdarg.h>
#include <inttypes.h>
#include <math.h>
int myPrintf(const char* frm, ...) {
  int cnt = 0, y, z; va_list arg; va_start(arg, frm);
  for (int i = 0; frm[i]; ++i)
	switch (frm[i]) {
	case '%': switch (frm[++i]) {
	case '%': putchar(frm[i]); ++cnt; break;
	case 'o': { unsigned int t = va_arg(arg, unsigned int); y = 0;
	  char s[0xb];
	  do {
		s[y++] = t % 8 + 0x30; t /= 8; ++cnt;
	  } while (t);
	  while (y)putchar(s[--y]);
	} break;
	case 'x': { unsigned int t = va_arg(arg, unsigned int); y = 0;
	  char s[0xb];
	  do {
		z = t % 0x10; s[y++] = z > 9 ? z + 0x57 : z + 0x30; t /= 0x10; ++cnt;
	  } while (t);
	  while (y)putchar(s[--y]);
	} break;
	case 'p': { unsigned long t = va_arg(arg, unsigned long); y = 0; putchar('0');
	  char s[0xb];
#ifdef _WIN32
	  do {
		z = t % 0x10; s[y++] = z > 9 ? z + 0x37 : z + 0x30; t /= 0x10; ++cnt;
	  } while (t);
#else
	  putchar('x');
	  do {
		z = t % 0x10; s[y++] = z > 9 ? z + 0x57 : z + 0x30; t /= 0x10; ++cnt;
	  } while (t);
#endif
	  if (y < 7)s[y++] = 0x30; while (y)putchar(s[--y]);
	} break;
	case 'c': { int t = va_arg(arg, int); putchar(t > 128 || t < -1 ? 63 : t); } break;
	case 'd': {
	  int t = va_arg(arg, int); y = 0; if (t < 0)putchar('-'), ++cnt;
	  char s[0xb];
	  do {
		s[y++] = t > 0 ? t % 10 + 0x30 : -(t % 10) + 0x30; t /= 10; ++cnt;
	  } while (t);
	  while (y)putchar(s[--y]);
	} break;
	case 's': {
	  const char* str = va_arg(arg, const char*);
	  for (int i = 0; str[i]; i++) {
		putchar(str[i]), ++cnt;
	  }
	} break;
	case 'l': switch (frm[++i]) {
	case 'l':if (frm[++i] == 'd') {
	  long long t = va_arg(arg, long long); y = 0; if (t < 0)putchar('-'), ++cnt;
	  char s[0x13];
	  do {
		s[y++] = t > 0 ? t % 10 + 0x30 : -(t % 10) + 0x30; t /= 10; ++cnt;
	  } while (t);
	  while (y)putchar(s[--y]);
	} else continue; break;
	case 'd': {
	  long t = va_arg(arg, long); y = 0; if (t < 0)putchar('-'), ++cnt;
	  char s[0xb];
	  do {
		s[y++] = t > 0 ? t % 10 + 0x30 : -(t % 10) + 0x30; t /= 10; ++cnt;
	  } while (t);
	  while (y)putchar(s[--y]);
	} break;
	case 'f': {
	  double l = va_arg(arg, double); long long t = (long long)l; l -= t;
	  y = z = 0; if (t < 0)putchar('-'), l = -l, ++cnt;
	  char s[26];
	  do {
		s[y++] = t > 0 ? t % 10 + 0x30 : -(t % 10) + 0x30; t /= 10; ++cnt;
	  } while (t);
	  while (y)putchar(s[--y]); s[y++] = 0x2e; t = 10;
	  do {
		s[y++] = (int)((l + 1e-6) * t) % 10 + 0x30; t *= 10; l -= (int)l; ++cnt;
	  } while (t < 1000001);
	  while (y > z)putchar(s[z++]);
	} break;
	} break;
	} break;
	default:putchar(frm[i]), ++cnt; break;
	}va_end(arg);
	return cnt;
}
int main() {
  myPrintf("INT32_MAX = %d\n", INT32_MAX);
  myPrintf("INT32_MIN = %d\n", INT32_MIN);
  myPrintf("INT32_MAX = %x\n", INT32_MAX);
  myPrintf("char = %c\n", -1);
  myPrintf("char = %lf\n", -801.235324);
  myPrintf("INT64_MAX = %lld\n", INT64_MAX);
  myPrintf("INT64_MIN = %lld\n", INT64_MIN);
  return 0;
}

输出

INT32_MAX = 2147483647
INT32_MIN = -2147483648
INT32_MAX = 7fffffff
char = 
char = -801.235324
INT64_MAX = 9223372036854775807
INT64_MIN = -9223372036854775808