问题
I am writing a function that saves data to a file in C, making use of the fprintf function. However, this requires a placeholder as one of its arguments. For example: %s for strings, %d for integers... What should I do if the data type is generic, that is, the programmer using this function can set the data type of the variable I am writing to the file to anything he wants? Thanks!
回答1:
you can open your file with the w+ inorder to write your data in binary format
Then you can use fwrite() to write data directly in binary form, intended to be read by fread() later.
回答2:
Since the type of the data is known only at run-time, you will have to:
generate the format string used by the fprintf function at run-time, or
choose between multiple harcoded format strings to pass to fprintf.
The choice between these two options could depend on how many different types you have to deal with, and/or how you know at run-time the type of your placeholder argument.
回答3:
Can try something like following :
Use a struct to know type of data while writing
typedef enum { String, Int, Char} datatype;
struct record{
datatype dt;
void* data;
};
int myfprintf(FILE* stream, struct record* rec){
switch(rec->dt){
case Char: return fprintf(stream, "%c", *((char*)(rec->data)));
case Int: return fprintf(stream, "%d", *((int*)rec->data));
case String: return fprintf(stream, "%s", (char*)rec->data);
//....
default: return fprintf(stream,"%s", "Error");
}
}
Then use myprintf passing the stream and the data of type record
Alternatively you can use a union too in similar fashion
With C11 you can do following :- (taken from here ):
#define printf_dec_format(x) _Generic((x), \
char: "%c", \
signed char: "%hhd", \
unsigned char: "%hhu", \
signed short: "%hd", \
unsigned short: "%hu", \
signed int: "%d", \
unsigned int: "%u", \
long int: "%ld", \
unsigned long int: "%lu", \
long long int: "%lld", \
unsigned long long int: "%llu", \
float: "%f", \
double: "%f", \
long double: "%Lf", \
char *: "%s", \
void *: "%p")
#define fprint(stream, x) fprintf(stream,printf_dec_format(x), x)
fprint(stdin,(char *)"P0W"); // for string literal
回答4:
C not supported generic except in void* I think , I've been working on a small project that make C a little bit Generic .. you can do what you want by set one of the arguments for the type say 0 for string and 1 for integers
then make an if-else statement then use printf for each one alone .
int print (FILE f,void*x,int type)
{
if(type==0)
return fprintf(f,"%s",(char*)x);
else
return fprintf(f,"%d",*(int*)x);
}
回答5:
C does not have a generic data type, so one must be created.
typedef enum {
Generic_int, Generic_float, Generic_double, Generic_string
} Generic_Type;
typedef struct {
Generic_Type type;
union {
int i;
float f;
double d;
char *s;
// other types
} u;
} Generic;
void Generic_printf(Generic *G) {
switch (G->type) {
case Generic_int:
printf("%d", G->u.i);
break;
case Generic_float:
printf("%.*e", FLT_DECIMAL_DIG, G->u.f);
break;
case Generic_double:
printf("%.*e", DBL_DECIMAL_DIG, G->u.d);
break;
case Generic_string:
printf("\"%s\"", G->u.s); // Enclose string in quotes
break;
// other
}
}
来源:https://stackoverflow.com/questions/20871314/generic-argument-for-fprintf-in-c