我正在尝试重新编程printf函数(大学项目)但%f导致我出现问题。我使用像这样的函数指针:
void (*fct[15])(void*) =
{printfs, printfc, printfd, printfd, printfl, printfx, printfX,
printfo, printfb, printfS, printfu, printfp, printff};
当使用右标志时,调用其中一个函数。典型的printfd将收到一个void *变量作为参数,并将这样做:
int nbr = (int)var; //var is a void* type variable
my_put_nbr(var); //handmade function wich displays numbers
事情是,出于一些奇怪的原因,当我为printff做同样的事情时,它没有用
float nbr = (float)var;
我收到了消息
error:指向预期浮点值的指针值float nbr =(float)var
我也尝试过这样的事情。如果我有
my_printf("%f", var); //with var = 12.34
然后我调用printff()函数,该函数应该:
int nbr1 = (int)(var / 1);
int nbr2 = (int)(var % 1);
所以我通常有nbr1 = 12和nbr2 = 34然后我会在'。'之间显示两者。但它仍然无法正常工作,我得到的信息是:
错误:无效操作数到二进制*(有'void *'和'int')int nbr1 =(int)(var * 1)
我不在意,所以如果你有任何线索,请告诉我。此外,我不能使用像printf()之类的命令,这是本练习的规则,所以不要告诉我解决方案隐藏在这里。
如果我正确理解你的问题,当你完全确定调用者部分时,在被调用的函数中,考虑到你在var
中收到了参数,你可以做
int
printf("%d", *(int *)var);
float
/ double
printf("%f", *(double *)var);
等等。
请注意,变量函数不存在float
类型,因为对于这些函数,由于默认参数提升,float
类型被提升为double
。
详细说明,您不会将传入指针强制转换/分配给所需类型(无效[类型不匹配]和不需要的类型)。相反,您将void *
参数强制转换为适当的调用者参数类型(基于您提到的标志),然后取消引用以获取该值。
这个比喻是基于C11
,第6.3.2.3章中提到的属性
指向
void
的指针可以转换为指向任何对象类型的指针。指向任何对象类型的指针可以转换为指向void
的指针并再次返回;结果应该等于原始指针。
它被称为双关语。指针惩罚是UB。最安全的方法是将void指针中的数据memcpy到float变量。
float x;
memcpy (&x, voidptr, sizeof(float));
你没有正确地调用va_args
。第二个参数必须是您期望从变量参数读取的数据类型,因为va_args
需要正确的大小才能知道从哪里获取下一个参数。
虽然使用数组来存储所有可能的函数可能看起来很聪明,但实际上当你有一个更简单,更易读的方法时,你实际上会让事情变得更难。它也可能更具扩展性。
switch(format_char)
{
case 'd':
print_an_int(va_args(args,int));
break;
case 'f':
print_an_float(va_args(args,float));
break;
}
尝试使用
int nbr = *((int *)var);
float nbr = *((float *)var);
将void指针var转换为整数/浮点指针,然后获取存储在该内存地址中的值并将值存储到变量中
代替
int nbr =(int)var;
float nbr =(float)was;
将存储在var中的地址转换为int / float。在这里,您只是转换地址而不是存储在该地址中的值。
而不是尝试从args
提取参数并将结果传递给fct[i]
,而是直接将args
传递给fct[i]
并让他们进行提取。唯一需要注意的是,你不能通过价值来传递。
fct[i](&args);
在每个printf *辅助函数中执行以下操作:
void printf_double (va_list *args) {
double val = va_arg(*args, double);
// print it
}
注意float
不是printf
的有效类型,因为float
在varargs调用中被提升为double
。