目前,我有以下两个功能:
void write_to_file(FILE *fp)
{
fprintf(fp, "stuff here: %d", 10);
/* 1000s of similar lines below */
}
和
void write_to_string(char *str)
{
sprintf(str, "stuff here: %d", 10);
/* 1000s of similar lines below */
}
我希望将其变形为单个功能。 我想过像这样的事情:
void write_somewhere(void *ptr, int to_file)
{
if (to_file) {
typedef fprintf myprintf;
} else {
typedef sprintf myprintf;
}
myprintf(ptr, "stuff here: %d", 10);
}
这不起作用,看起来很难看。
由于fprintf
和sprintf
的签名不同,如下所示,
int fprintf(FILE *stream, const char *format, …);
int sprintf(char *buffer, const char *format, …);
是否可以做类似的事情,
void write_somewhere(void *ptr, void *func)
{
func(ptr, "stuff here: %d", 10);
}
修改 根据下面的Alter的回答,这就是我所拥有的,但它并没有按预期工作,并且在尝试打印write_somewhere()函数中的值时打印出垃圾值:
#include <stdio.h>
#include <stdarg.h>
typedef int (*myprintf_t) (void *, const char *, ...);
int myfprintf(void *ptr, const char *format, ...)
{
va_list args;
int ret;
va_start(args, format);
ret = vfprintf(ptr, format, args);
va_end(args);
return ret;
}
int mysprintf(void *ptr, const char *format, ...)
{
va_list args;
int ret;
va_start(args, format);
ret = vsprintf(ptr, format, args);
va_end(args);
return ret;
}
void write_somewhere(void *ptr, myprintf_t myprintf, const char *format, ...)
{
va_list args;
int ret;
va_start(args, format);
ret = myprintf(ptr, format, args);
va_end(args);
return ret;
}
int main(void)
{
char s[100];
int i = 100;
/* This works */
write_somewhere(stdout, myprintf, "Hello world");
/* This prints out garbage */
write_somewhere(stdout, myprintf, "Hello world, I am %d", i);
write_somewhere(s, mysprintf);
return 0;
}
答案 0 :(得分:9)
Jen的回答是正确的,但在这种情况下,您可以使用指向函数的指针将ptr
重定向到v*printf
:
#include <stdio.h>
#include <stdarg.h>
int myfprintf(void *ptr, const char *format, ...)
{
va_list args;
int ret;
va_start(args, format);
ret = vfprintf(ptr, format, args);
va_end(args);
return ret;
}
int mysprintf(void *ptr, const char *format, ...)
{
va_list args;
int ret;
va_start(args, format);
ret = vsprintf(ptr, format, args);
va_end(args);
return ret;
}
void write_somewhere(void *ptr, int (*myprintf)(void *, const char *, ...))
{
myprintf(ptr, "stuff here");
}
int main(void)
{
char s[100];
write_somewhere(stdout, myfprintf);
write_somewhere(s, mysprintf);
return 0;
}
上次修改
您似乎想要将一些额外参数传递给write_somewhere
,在这种情况下我建议:
#include <stdio.h>
#include <stdarg.h>
#define TO_FILE 0
#define TO_STRING 1
void write_somewhere(int where, void *ptr, const char *format, ...)
{
#define myprintf(ptr, ...) \
(where == TO_FILE ? vfprintf(ptr, __VA_ARGS__) : vsprintf(ptr, __VA_ARGS__))
va_list args;
va_start(args, format);
myprintf(ptr, format, args);
/* more stuff */
va_end(args);
#undef myprintf
}
int main(void)
{
char s[100];
write_somewhere(TO_FILE, stdout, "%u\n", 10);
write_somewhere(TO_STRING, s, "Hello");
printf("%s\n", s);
return 0;
}
答案 1 :(得分:7)
C语言保证所有函数指针具有相同的表示。你的多态函数只需要原型化为接受任何函数指针,比如void (*funcptr)(void)
。请注意,ptr-to-void 不是一个函数指针(它是一个对象指针),并且可能无法保存函数指针。
当然,如果您知道它是哪种类型,您只能调用该函数。所以你需要某种方式来区别对待,就像printf通过查看格式一样。如果调用的参数与其原型不匹配,则行为未定义。
答案 2 :(得分:3)
不是您确切问题的答案,但不是像您一样编写write_something()
,而是可以稍微更改结构:
void write_somewhere(void *ptr, int to_file)
{
if (to_file) {
fprintf( (FILE*) ptr, "stuff here");
} else {
sprintf( (char*) ptr, "stuff here");
}
}
但是,要严格回答你的问题......
如您所见,您尝试过的typedef行不起作用。 typedef
是编译时操作,而不是运行时操作。
但是,您可以做的是为函数指针定义一个匹配fprintf()
和sprintf()
函数的类型:
typedef int (*someprintf_ptr)(FILE *stream, const char *format, …);
write_somewhere()
看起来像是:
void write_somewhere(void *ptr, someprintf_ptr func)
{
func(ptr, "stuff here");
}
/* with calls looking like... */
write_somewhere( (void *)a_file_ptr, (someprintf_ptr)(fprintf));
答案 3 :(得分:2)
你的write_something函数必须是:
void write_something(void (*function)(), int to_file)
{
....
}
答案 4 :(得分:1)
尝试将myprintf设为函数
void write_somewhere(void *ptr, int to_file)
{
myprintf(to_file, ptr, "stuff here");
// do stuff
/* 1000s of similar lines below */
}
void myprintf( int to_file, void *ptr, char *output )
{
if (to_file)
fprintf( ptr, output );
else
sprintf( ptr, output );
}
答案 5 :(得分:1)
让我试试:
struct target {
int (*tgtfunction)();
void* ptr;
}
struct target mktarget_file(FILE * fp) {
struct target tgt = { .tgtfuntion = vfprintf, .ptr = fp };
return tgt;
}
struct target mktarget_string(char * str) {
struct target tgt = { .tgtfuntion = vsprintf; .ptr = str };
return tgt;
}
void tgtprintf(struct target * target, char * fmt, ...) {
va_list ap;
va_start(ap, target);
int ret = target.tgtfunction(target.ptr, fmt, ap);
va_end(ap);
return ret;
}
void write_stuff(struct target * target)
{
tgtprintf(target, "stuff here");
/* 1000s of similar lines below */
}
应该做你想做的事:为你想要的目标创建一个struct target
,然后调用write_stuff来写你的东西。
请注意sprintf内容可能需要改进,因为每个字符串都写入相同的位置而不是追加,并且没有检查可用空间。但一般概念可以这样开始。