Products > Programming
GCC ARM32 compiler too clever, or not clever enough?
Nominal Animal:
I occasionally use an array of structures containing the name, optionally a type identifier, and a function pointer:
--- Code: ---enum {
FUNCTYPE_NONE = 0,
FUNCTYPE_FLOAT_UNARY, /* Returns a float, takes one float as an argument */
FUNCTYPE_FLOAT_BINARY, /* Returns a float, takes two floats as arguments */
};
typedef struct {
const char *name;
int type;
union {
float (*float_unary)(float); /* .type = FUNCTYPE_FLOAT_UNARY */
float (*float_binary)(float, float); /* .type = FUNCTYPE_FLOAT_BINARY */
};
} function_descriptor;
const function_descriptor func[] =
{
{ .name = "sin", .type = FUNCTYPE_FLOAT_UNARY, .float_unary = sinf },
/* Other functions omitted */
{ .name = NULL, .type = FUNCTYPE_NONE }
};
#define funcs ((sizeof func / sizeof func[0]) - 1)
--- End code ---
Valid indexes are 0 through funcs-1, inclusive; or you can loop until .name==NULL or .type==FUNCTYPE_NONE.
This is useful when one needs to execute a function when given its name as a string:
--- Code: ---int exec_float_unary(const char *name, float *result, float arg);
int exec_float_binary(const char *name, float *result, float leftarg, float rightarg);
--- End code ---
where the return value is 0 if successful and nonzero for error codes, result points to where the result is stored, and arg, leftarg, and rightarg are arguments passed to the function.
(It is pretty obvious that the most recent case I used this at was a calculator/expression evaluator...)
In case of an extensible calculator/expression evaluator -type thingy on a fully featured OS, I like to use
--- Code: ---static size_t funcs_max = 0;
static size_t funcs = 0;
static function_descriptor *func = NULL;
int register_float_unary(const char *name, float (*func)(float));
int register_float_binary(const char *name, float (*func)(float, float));
--- End code ---
so that plugins can provide new functions ELF-magically using
--- Code: ---__attribute__ ((__constructor__))
static void register_functions(void)
{
register_float_unary("sin", sinf);
register_float_unary("cos", cosf);
register_float_unary("tan", tanf);
register_float_binary("atan2", atan2f);
}
--- End code ---
where the constructor function attribute causes the linker to add the address of that function into an ELF section, so that either the startup code (if static) or dynamic linker (if dynamic) will execute it when the ELF object is loaded.
Navigation
[0] Message Index
[*] Previous page
Go to full version