创建一个可变参数函数,打印任何类型的格式(“c”,“f”,“i”,“s”),但不起作用

Eha*_*yed 5 c printf struct function-pointers variadic-functions

我创建了一个结构体,它将格式字符和指向根据格式化程序打印的函数的指针进行分组。

typedef struct formatter
{
  char spec;
  void (*print)(va_list);
} fmt;

Run Code Online (Sandbox Code Playgroud)

然后,我创建了打印每种格式的函数。

void print_char(va_list args)
{
  printf("%c", va_arg(args, int));
}

void print_int(va_list args)
{
  printf("%d", va_arg(args, int));
}

void print_float(va_list args)
{
  printf("%f", va_arg(args, double));
}

void print_string(va_list args)
{
  char *spec = va_arg(args, char *);
  if (spec == NULL)
  {
    printf("(nil)");
    return;
  }
  printf("%s", spec);
}

Run Code Online (Sandbox Code Playgroud)

在主可变参数函数中,我创建了一个结构数组以便对其进行循环。

void print_all(const char *const format, ...)
{
  fmt f[] = {
      {'c', print_char},
      {'i', print_int},
      {'f', print_float},
      {'s', print_string},
      {'\0', NULL}};

  int i = 0, j;
  char *separator = "";
  va_list args;
  va_start(args, format);

  if (format == NULL)
  {
    return;
  }

  while (format[i] != '\0')
  {
    j = 0;
    while (f[j].spec)
    {
      if (f[j].spec == format[i])
      {
        printf("%s", separator);
        f[j].print(args);
        separator = ", ";
        break;
      }
      j++;
    }
    i++;
  }
  printf("\n");
  va_end(args);
}

Run Code Online (Sandbox Code Playgroud)

当我编译程序并测试以下情况时,问题来了:

int main(void)
{
  print_all("ceis", 'B', 3, "stSchool");
  return (0);
}
Run Code Online (Sandbox Code Playgroud)

它打印 B, 66,而不是打印 B, 3, stSchool

我需要知道问题出在哪里。

我预计问题会出现在每个函数中的 va_arg 中,但是根据我对可变参数函数的不太详细的了解,我无法更改某些内容。而且我不想使用开关盒来实现它,以便模块化我的程序。

Kam*_*Cuk 3

va_list按值传递给多个函数是无效的。您必须传递一个指向 的指针va_list

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

typedef struct formatter {
  char spec;
  void (*print)(va_list*);
} fmt;

void print_char(va_list *args) {
  printf("%c", va_arg(*args, int));
}

void print_int(va_list *args) {
  printf("%d", va_arg(*args, int));
}

void print_float(va_list *args) {
  printf("%f", va_arg(*args, double));
}

void print_string(va_list *args) {
  char *spec = va_arg(*args, char *);
  if (spec == NULL) {
    printf("(nil)");
    return;
  }
  printf("%s", spec);
}

void print_all(const char *const format, ...) {
  fmt f[] = {
      {'c', print_char},
      {'i', print_int},
      {'f', print_float},
      {'s', print_string},
      {'\0', NULL}};
  const char *separator = "";
  va_list args;
  va_start(args, format);

  if (format == NULL) {
    return;
  }

  for (int i = 0; format[i] != '\0'; ++i) {
    for (int j = 0; f[j].spec; f++) {
      if (f[j].spec == format[i]) {
        printf("%s", separator);
        f[j].print(&args);
        separator = ", ";
        break;
      }
    }
  }
  printf("\n");
  va_end(args);
}

int main(void) {
  print_all("cis", 'B', 3, "stSchool");
}
Run Code Online (Sandbox Code Playgroud)