在没有标准库的情况下在 C 中将数字打印为字符串

Printing number as string in C without stdlibs

我正在尝试做类似的事情 printf("My age is: %d\n", age); 但我无权访问标准库。相反,我可以访问的打印功能 print() 只需要一个 const char*.

我不允许使用 sprintfitoa 或任何类似的东西,因为那根本不可用。有什么办法可以打印号码吗?

P.S。如果您需要更多上下文,https://github.com/SpinalHDL/VexRiscv/issues/215 是 :)

提前致谢

有点笨拙。您可以从低端开始获取数字,使用 % 10(模数)隔离个位数字和 / 10(整数除法)将数字右移。你在一个循环中这样做,直到 int 下降到零。如果整个事情是零,你必须自己设置 '0' 字符,因为循环将不会执行第一次迭代。

您需要在每个数字上添加'0'使其成为ASCII数字,并且您需要将连续的数字存储在一个字符数组中。

您需要在末尾附加一个 NUL ('\0') 字符作为字符串终止符。

然后你需要反转整个字符串,因为数字的顺序是相反的。或者,您可以从末尾填充 char 数组,但是您必须将整个字符串(包括 NUL)复制到缓冲区的前面。

如果整数可以是负数,你需要记住这一点,用零减去它变成正数,并在倒数之前在末尾加上'-'。

听起来很多,但 long2str 函数大约需要 20 行。

编辑:也有一个递归解决方案。下降到所需的深度,并在返回的路上保存数字,避免了逆序问题(包括减号),并创建了没有填充的字符串。

//.. Recursive solution.

//.. Base case.

void l2s_r (char **p, long int n)

{
    char d = (n % 10) + '0';
    if (n >= 10) l2s_r (p, n / 10);
    *((*p)++) = d;
}

//.. Wrapper case.

char *l2s (long int n)

{
static char s[24];
char *p = s;

    if (n < 0) { *p++ = '-'; n = 0 - n; }
    l2s_r (& p, n);
    *p = '[=10=]';
    return (s);
}

像这样

int length(long long int no) 
{
 int count = 0;
 while (no != 0) 
 {
    no = no/10;
        count++;
 }
 return count;
}

void printer(long long int no)
{
   long long int temp = no;
   int i=0;
   char arr[10000];    
   i = length(no)-1;
   //Extract digits and fill `arr` backwards
   while(temp > 0)
   {
        arr[i] = (temp%10 + '0');    
        i--;
        temp = temp/10;
   }
   arr[length(no)] = '\n'; 
  char* p = &arr[0];
  println(p); //specific to: https://github.com/SpinalHDL/VexRiscv/blob/master/src/main/c/murax/hello_world/src/main.c
  //return p;
}

因为已经一周了(不喜欢为深夜硬件作业提供代码),所以一些代码可以增加 描述性答案。

一种从右到左形成数字字符串的从 2 到 36 的方法。

它通过形成负绝对值来避免0 - INT_MIN的未定义行为。

它使用 div() 而不是 /, % 来避免 C89 的实现行为。

使用 do 循环,因此 print_int(0, base) 打印 "0".

#include <assert.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
extern int print(const char *);

// Enough room for INT_MIN as a binary string.
#define MY_ITOA_BUF_SIZE (sizeof(int)*CHAR_BIT + 2)
#define MY_ITOA_BASE_MIN 2
#define MY_ITOA_BASE_MAX 36

// Negative values result in a string beginning with a '-' for all bases.
// Adjust as desired.
void print_int(int i, int base) {
  char buf[MY_ITOA_BUF_SIZE];
  char *p = &buf[sizeof buf - 1]; // Start from the "right".
  assert(base >= MY_ITOA_BASE_MIN && base <= MY_ITOA_BASE_MAX);

  *p = '[=10=]';
  int value = i < 0 ? i : -i;  // negative absolute value
  do {
    div_t qr = div(value, base);
    *(--p) = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-qr.rem];  // Table look up
    value = qr.quot;
  } while (value);

  if (i < 0) {
    *(--p) = '-';
  }

  print(p);  // Like fputs(p, stdout)
}