printf()函数的实现

4

我正在制作一个业余内核,并尝试实现printf()函数。

以下是我的实现:

void kprint(uint8_t *format, ...) {
  va_list ap;
  va_start(ap, format);

  uint8_t *ptr;

  for (ptr = format; *ptr != '\0'; ptr++) {
    if (*ptr == '%') {
      ptr++;
      switch (*ptr) {
        case 's':
          puts(va_arg(ap, uint8_t *), 0x0F, xPos, yPos);
          break;
      }
    } else {
      puts(ptr, 0x0F, xPos, yPos);
      ptr++;
    }
  }

  va_end(ap);
}

当我使用这个函数打印“Hello World!”时,它返回以下内容:
"Hello %sllo %so %sWorld"

以下是函数调用:

kprint("Hello %s", "World");

5
似乎在未遇到“%”时,您将“ptr”递增了两次。另外,请不要忘记将“%%”视为“%”。 - Jean-François Fabre
1
你尝试过将其作为简单用户模式程序的一部分进行调试吗? - Jabberwocky
4
puts 函数会打印字符串剩余部分。你需要使用 putc(*ptr) - Jean-François Fabre
@Jean-FrançoisFabre,我删除了指针递增并在else块中用putc()替换了puts(),但现在它只打印给定的参数。 - msk
puts(va_arg(ap, uint8_t *), 0x0F, xPos, yPos); 这行代码是有问题的。它会让 xposypos 的值保持不变,即错误的值。 - Jasen
2个回答

8
主要问题在于你使用puts打印其余字符串而不是当前字符。
 } else {
   puts(ptr, 0x0F, xPos, yPos);
   ptr++;
}

另外,你在循环中已经对ptr进行了递增操作。这个操作可以用来消耗格式参数,但在这种情况下不需要。

以下是一个可工作的实现(不使用奇怪的puts原型),可以在标准系统上正常运行(在Windows GCC上进行了测试):

#include <stdio.h>
#include <stdint.h>
#include <stdarg.h>

void zprintf(uint8_t *format, ...)
  {
      va_list ap;
      va_start(ap, format);

      uint8_t *ptr;

      for (ptr = format; *ptr != '\0'; ptr++) {
          if (*ptr == '%') {
              ptr++;
              switch (*ptr) {
                  case 's':
                      fputs(va_arg(ap, uint8_t *),stdout);
                      break;
                 case '%':
                      putchar('%');
                      break;
              }
             } else {
               putchar(*ptr);

            }
           }

           va_end(ap);
}

int main(){

    zprintf("%% Hello %s\n","World");    
    return 0;
}

打印:

% Hello World

(作为附加功能,该实现处理了转义的 % 字符)
只使用您特殊的 puts 实现,您可以更改
 } else {
   puts(ptr, 0x0F, xPos, yPos);
   ptr++;
}

转变为工作中:

 } else {
   char c[2];
   c[0] = *ptr; c[1] = '\0';
   puts(c, 0x0F, xPos, yPos);
 }

虽然不太好,但可以解决问题 :)


请在您的平台上检查 putc 原型,或创建一个仅包含1个字符的2大小的char *(哎呀)。 - Jean-François Fabre
现在它可以工作了。我还改变了我的puts原型,所以现在它只接受char类型。在编辑之前,我仍然会尝试按照你的方式来做。 - msk
1
puts appends '\n'. Suggest fputs(va_arg(ap, uint8_t *), stdout); - chux - Reinstate Monica
@chux 我自己实现了puts函数。 - msk
当编译器看到这些名称覆盖了它们的内置名称时,有时候它们也会感到困惑。这就是我改用 zprintf 的原因。 - Jean-François Fabre
显示剩余2条评论

3
void kprint(char *format, ...) 
{
    va_list ap;
    va_start(ap, format);

    char *ptr = format;

  while(*ptr)
  {
    if (*ptr == '%') 
    {
      ptr++;
      switch (*ptr++) 
      {
        case 's':
          printf("%s", va_arg(ap, char *));
          break;
      }
    } 
    else 
    {
      putchar(*ptr++);
    }
  }

  va_end(ap);
}

int main()
{
    kprint("Hello %s World%s", "AAAAA", " BBBBBB");

    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接