在尝试重新编码 printf 时收到使用 void * 的警告

问题描述 投票:0回答:1

我正在尝试设置一个函数数组,这些函数接受需要不同变量的函数(例如,

my_putchar
需要一个
char
,而
my_put_nbr
需要一个
int
),所以我决定定义它使用
void *
。虽然它确实有效,但在编译时会发出警告。

#include "stdarg.h"
#include "my.h"

int put_perc(void)
{
    my_putchar('%');
}

int read_print(const char *s, int i, va_list args)
{
    int k = 0;
    char guide[] = "cdis%f";
    int (*functions[])(void *) = {my_putchar, my_put_nbr,
        my_put_nbr, my_putstr, put_perc, my_put_float};

    for (k = 0; s[i + 1] != guide[k]; k++);
    functions[k](va_arg(args, void *));
}

void mini_printf(const char *s, ...)
{
    int k = 0;
    va_list args;
    char guide[] = "cdis%";

    va_start(args, s);
    for (int i = 0; i < my_strlen(s); i++) {
        if (s[i] == '%') {
            read_print(s, i, args);
            i++;
        } else {
            my_putchar(s[i]);
        }
    }
    va_end(args);
}

void main(void)
{
    mini_printf("%s %s %s letter is %c followed by %d and %i.\nfloats %f  \nlets also test     this out, %s 100%%\n", "come", "on", "WORK", 'h', 58, 12, 55.756567575658, "this should work");
}

这些是我收到的警告。

my_printf.c: In function ‘read_print’:
my_printf.c:20:35: warning: initialization of ‘int (*)(void *)’ from incompatible pointer type ‘void (*)(char)’ [-Wincompatible-pointer-types]
   20 |     int (*functions[])(void *) = {my_putchar, my_put_nbr,
      |                                   ^~~~~~~~~~
my_printf.c:20:35: note: (near initialization for ‘functions[0]’)
my_printf.c:20:47: warning: initialization of ‘int (*)(void *)’ from incompatible pointer type ‘int (*)(int)’ [-Wincompatible-pointer-types]
   20 |     int (*functions[])(void *) = {my_putchar, my_put_nbr,
      |                                               ^~~~~~~~~~
my_printf.c:20:47: note: (near initialization for ‘functions[1]’)
my_printf.c:21:9: warning: initialization of ‘int (*)(void *)’ from incompatible pointer type ‘int (*)(int)’ [-Wincompatible-pointer-types]
   21 |         my_put_nbr, my_putstr, put_perc, my_put_float};
      |         ^~~~~~~~~~
my_printf.c:21:9: note: (near initialization for ‘functions[2]’)
my_printf.c:21:21: warning: initialization of ‘int (*)(void *)’ from incompatible pointer type ‘int (*)(const char *)’ [-Wincompatible-pointer-types]
   21 |         my_put_nbr, my_putstr, put_perc, my_put_float};
      |                     ^~~~~~~~~
my_printf.c:21:21: note: (near initialization for ‘functions[3]’)
my_printf.c:21:32: warning: initialization of ‘int (*)(void *)’ from incompatible pointer type ‘int (*)(void)’ [-Wincompatible-pointer-types]
   21 |         my_put_nbr, my_putstr, put_perc, my_put_float};
      |                                ^~~~~~~~
my_printf.c:21:32: note: (near initialization for ‘functions[4]’)
my_printf.c:21:42: warning: initialization of ‘int (*)(void *)’ from incompatible pointer type ‘int (*)(double)’ [-Wincompatible-pointer-types]
   21 |         my_put_nbr, my_putstr, put_perc, my_put_float};
      |                                          ^~~~~~~~~~~~
my_printf.c:21:42: note: (near initialization for ‘functions[5]’)

我真的不知道如何解决这个问题,因为我只是认为

void *
充当了变量类型的包罗万象的角色。 (这只是我编码的第三周,所以我还没有那么有经验)

c compiler-warnings void suppress-warnings
1个回答
0
投票

我只是认为 void * 充当了变量类型的包罗万象的角色。

不完全是,不。事实是,任何 pointer 类型都可以转换为

void *
并返回。 (请注意,回到原始指针类型。不仅仅是any指针类型。)

但是这里...

int (*functions[])(void *)

...是一个指向函数的指针数组,返回 int

 并以 
void *
 作为参数

然而,您的实际函数采用非指针类型(

char

int
void
double
)或
const指针(const char *
)。如果不进行强制转换,这些都无法转换为 
void *

那只是你麻烦的开始。例如,您的

put_perc

 不接受任何争论。不过,您将
调用作为带有参数的函数,将其传递给堆栈中的下一个void *
...我看到您的这个构造将发生各种“有趣”的事情。

我建议,不要调用

read_print

 并期望它“自动运行”,而是阅读 中 
'c'
 后面的转换说明符(
's'
'd'
'%'
...) 
mini_printf
 格式,对其执行 
switch
,并在相应的 
case
 中执行正确的操作,例如打印 
'%'
 或获取堆栈中的 
int
 并将其传递给 
my_put_nbr
。这样就干净很多,
很多

© www.soinside.com 2019 - 2024. All rights reserved.