, , , , C. , , , , , . . , , .
, , , . :
typedef void* GenericFunction(int argc, void** args);
, , , , :
void* MyCallback(int argc, void** args)
{
assert(argc == 2);
...
return 0;
}
, , , - :
struct Variant
{
void* ptr;
const char* type_name;
};
struct Variant to_variant(void* ptr, const char* type_name)
{
struct Variant new_var;
new_var.ptr = ptr;
new_var.type_name = type_name;
return new_var;
}
void* from_variant(struct Variant* var, const char* type_name)
{
assert(strcmp(var->type_name, type_name) == 0 && "Type mismatch!");
return var->ptr;
}
void* pop_variant(struct Variant** args, const char* type_name)
{
struct Variant* var = *args;
assert(var->ptr && "Trying to pop off the end of the argument stack!");
assert(strcmp(var->type_name, type_name) == 0 && "Type mismatch!");
++*args;
return var->ptr;
}
:
#define TO_VARIANT(val, type) to_variant(&val,
#define FROM_VARIANT(var, type) *(type*)from_variant(&var,
#define POP_VARIANT(args, type) *(type*)pop_variant(&args,
typedef struct Variant* GenericFunction(struct Variant* args);
:
struct Variant* MyCallback(struct Variant* args)
{
int arg1 = POP_VARIANT(args, int);
float arg2 = POP_VARIANT(args, float);
...
return 0;
}
- , , MyCallback type_name.
Such a function can be useful if your codebase supports callbacks to dynamically typed scripting languages, since scripting languages ββshould not make cast types in their code (as a rule, they should be a little more secure). Type names can then be used to automatically convert arguments to native scripting language types dynamically using these fields type_name.