I have a function like:
typedef struct
{
bool x;
bool y;
bool z;
} myStruct;
static void myFunction(const myStruct *pTomystruct_out)
{
if (pTomystruct_out->x == TRUE)
{
/*Do Something*/
}
}
Now for some debug purpose I want to add debug code to set the pointer parameter always to TRUE.
Within the function before the if statement I want to do something like:
pTomystruct_out.x = TRUE /*This is not the correct way*/
How to do this in the right way?
Thanks!
pTomystruct_out is a pointer, so you have to dereference that for manipulating what is pointed.
You can use * opetator to dereference:
(*pTomystruct_out).x = TRUE;
Also you can use -> operator where A->B means (*A).B:
pTomystruct_out->x = TRUE;
Also, this is not enough because the pointer pTomystruct_out is marked as const.
You can use a cast to non-const pointer for having it allow modifications.
((myStruct*)pTomystruct_out)->x = TRUE;
This is syntactically collect, but it may be dangerous to modify the object that is thought not to be modified. Creating a copy of the object and modifying the copy is safer.
typedef struct
{
bool x;
bool y;
bool z;
} myStruct;
#if 1 /* debug mode */
static void myFunction(const myStruct *pTomystruct_out_arg) /* change argument name */
{
myStruct pTomystruct_debug_temp = *pTomystruct_out_arg; /* make a copy */
myStruct *pTomystruct_out = &pTomystruct_debug_temp; /* declare a variable with original argument name */
pTomystruct_out->x = TRUE; /* modify the copy */
#else
static void myFunction(const myStruct *pTomystruct_out)
{
#endif
if (pTomystruct_out->x == TRUE)
{
/*Do Something*/
}
}
As mentioned in previous answer, the parameter is const, disabling modifications to that parameter. You probably don't want it to be const.
To add debug code, you can make use of macros. You can have a header file contain macros, like seen below:
#define DEBUG
Or:
#define DEBUG 1
Included a header with this macro allows you to write your function as follows:
static void myFunction(const myStruct *pTomystruct_out)
{
#ifdef DEBUG
pTomystruct_out.x = TRUE
#endif
}
If you used the latter macro, #define DEBUG 1 (which I recommend), you can use an if-statement instead:
static void myFunction(const myStruct *pTomystruct_out)
{
#if DEBUG
pTomystruct_out.x = TRUE
#endif
}
I recommend using #define DEBUG 1, because then you don't have to comment out the macro whenever you don't want it. You can just set it to 0.
If you don't want a header file, you can use the -D flag using gcc, like gcc <INPUTFILE> -DDEBUG.
Related
I'm experimenting with memory management and trying to create something that will help with it in any way. Right now I'm trying to think is there any way to repeat the 'defer' functionality from Go in C.
Fast example for those who don't know what defer is:
package main
import "fmt"
func main() {
defer fmt.Println("1")
defer fmt.Println("2")
defer fmt.Println("3")
return
}
will print
3
2
1
So I'm thinking about some macros that will push the function with params to some stack and will call them when the function exit is called. Something like this:
int func(void)
{
MEMSTACK_INIT;
char * string = NULL;
node_t * node = NULL;
MEMSTACK_PUSH(free(string));
MEMSTACK_PUSH(NodeFree(&node));
<..>
switch (something)
{
case ONE : RETURN ERROR_ONE;
case TWO : RETURN ERROR_TWO;
case THR :
switch (something else)
{
<.. Many more code ..>
}
}
RETURN ERROR_GOOD;
}
Is there a way (except for making my own preprocessor, of course), to store somewhere a function call with params? In other words I want the previous code to be preprocessed in something like this:
int func(void)
{
<.. Some MEMSTACK initialisation stuff (if needed) ..>
char * string = NULL;
node_t * node = NULL;
<..>
switch (something)
{
case ONE :
free(string);
NodeFree(&node);
return ERROR_ONE;
case TWO :
free(string);
NodeFree(&node);
return ERROR_TWO;
case THR :
switch (something else)
{
<.. Many more code ..>
}
}
free(string);
NodeFree(&node);
return ERROR_GOOD;
}
It would be good thing for functions who require a lot of cleanup before exit.
Yes, yes, I know about goto cleanup trick.
I'm experimenting with memory management and trying to create something that will help with it in any way.
A good approach is to have only one return in any function. Possibly marked with a label (yes, so can gotoit, but this is also often discouraged). And of course: Be always sure to know who owns allocated memory and when (and where) ownership is transferred!
Now, let's...
[..] repeat the 'defer' functionality from Go in C.
First, in order to defer the call, we need to store the function (a pointer to it) as well as the evaluated arguments. Since C is statically typed, we need to unify that in a single type:
struct Fn {
void * parameters; // pointer to memory where the parameters are stored
void (*function)(void *); // pointer to function able to unpack parameters from above
struct Fn * next; // we want a stack, so ...
};
For each function that we are going to eventually defer, we need a way to store it's parameters. So we define a struct capable of holding the parameters and a function that is able to unpack the parameters from that struct:
#define MAKE_DEFERRABLE(name, N, ...) \
struct deferred_ ## name ## _parameters { PARAMS(N, __VA_ARGS__) }; \
void deferred_ ## name (void * p) { \
struct deferred_ ## name ## _parameters * parameters = p; \
printf(" -- Calling deferred " #name "\n"); \
(void)name(CPARAMS(N)); \
}
The N is the number of arguments. There are tricks to infer that from the __VA_ARGS__, but I'll leave that as an exercise for the reader. That macro contains two other macro expansions, PARAMS and CPARAMS. The former expands into a list suitable to define the struct contents. The later expands into code to extract the struct members as arguments:
#define PARAM_0(...)
#define PARAM_1(type, ...) type p1; PARAM_0(__VA_ARGS__)
#define PARAM_2(type, ...) type p2; PARAM_1(__VA_ARGS__)
#define PARAM_3(type, ...) type p3; PARAM_2(__VA_ARGS__)
#define PARAM_4(type, ...) type p4; PARAM_3(__VA_ARGS__)
#define PARAMS(N, ...) SPLICE(PARAM_, N)(__VA_ARGS__)
#define CPARAM_0
#define CPARAM_1 parameters->p1
#define CPARAM_2 parameters->p2, CPARAM_1
#define CPARAM_3 parameters->p3, CPARAM_2
#define CPARAM_4 parameters->p4, CPARAM_3
#define CPARAMS(N) SPLICE(CPARAM_, N)
If we'd want to defer functions with more than 4 parameters then this would need to be adjusted. The SPLICE is a nice little helper:
#define SPLICE_2(l,r) l##r
#define SPLICE_1(l,r) SPLICE_2(l,r)
#define SPLICE(l,r) SPLICE_1(l,r)
Next, we need to store the deferred functions somehow. For simplicity I choose to allocate them dynamically and keep a global pointer to the most recent:
struct Fn * deferred_fns = NULL;
Obviously you can extend this in many directions: Using (bounded) static storage, making it thread local, using per function deferred_fns, using alloca, ...
... but here's the simple, not production-ready (MISSING ERROR CHECKS) variant:
#define DEFER(name, N, ...) \
do { \
printf(" -- Deferring a call to " #name "\n"); \
if (deferred_fns == NULL) { \
deferred_fns = malloc(sizeof(*deferred_fns)); \
deferred_fns->next = NULL; \
} else { \
struct Fn * f = malloc(sizeof(*f)); \
f->next = deferred_fns; \
deferred_fns = f; \
} \
deferred_fns->function = &(deferred_ ## name); \
struct deferred_ ## name ##_parameters * parameters = malloc(sizeof(*parameters)); \
SPARAMS(N,__VA_ARGS__); \
deferred_fns->parameters = parameters; \
} while(0)
This just allocates a new struct Fn, makes it the top of the stack (read singly-linked list deferred_fns) and sets its members accordingly. The important SPARAMS saves the parameters into the corresponding struct:
#define SPARAM_0(...)
#define SPARAM_1(value, ...) parameters->p1 = (value); SPARAM_0(__VA_ARGS__)
#define SPARAM_2(value, ...) parameters->p2 = (value); SPARAM_1(__VA_ARGS__)
#define SPARAM_3(value, ...) parameters->p3 = (value); SPARAM_2(__VA_ARGS__)
#define SPARAM_4(value, ...) parameters->p4 = (value); SPARAM_3(__VA_ARGS__)
#define SPARAMS(N, ...) SPLICE(SPARAM_, N)(__VA_ARGS__)
Note: This fixes the order of parameter evaluation by making them evaluate from last to first. C does not mandate an evaluation order.
Finally, all that's left is a convenient way to run these deferred functions:
void run_deferred_fns(void) {
while (deferred_fns != NULL) {
deferred_fns->function(deferred_fns->parameters);
free(deferred_fns->parameters);
struct Fn * bye = deferred_fns;
deferred_fns = deferred_fns->next;
free(bye);
}
}
A small test:
void foo(int x) {
printf("foo: %d\n", x);
}
void bar(void) {
puts("bar");
}
void baz(int x, double y) {
printf("baz: %d %f\n", x, y);
}
MAKE_DEFERRABLE(foo, 1, int);
MAKE_DEFERRABLE(bar, 0);
MAKE_DEFERRABLE(baz, 2, int, double);
int main(void) {
DEFER(foo, 1, 42);
DEFER(bar, 0);
DEFER(foo, 1, 21);
DEFER(baz, 2, 42, 3.14);
run_deferred_fns();
return 0;
}
In order to achieve the same behavior as in your example, make deferred_fns a local variable, and pass that as parameter to run_deferred_fns. Wrap in simple macros, done:
#define PREPARE_DEFERRED_FNS struct Fn * deferred_fns = NULL;
#define RETURN(x) do { run_deferred_fns(deferred_fns); return (x); } while (0)
Welcome to insanity.
Note: My solution works at the "source level". By that I mean that you need to specify defer-able functions in the source code. That implies that you cannot, for example, defer a function loaded through dlopen. There's also a different approach, working at the ABI level, if you will: avcall, part of libffcall.
Now, I need really need my parentheses ... lots of them (())))(()(((()
I don't have much experience in Object oriented programming.I am trying to create an object in c which will have its own methods.
I have declared structure which have pointers to function. All instance of this variable are going to point same function. But currently I need to initialize every instance of variable as in main (Line 1 and Line 2). So is there any method that will initialize its default value when I declare it?
#include <stdio.h>
#include <stdlib.h>
typedef struct serialStr Serial;
struct serialStr
{
void(*init)(Serial*);
void(*open)();
void(*close)();
};
void open()
{
printf("Open Port Success\n");
return;
}
void close()
{
printf("Close port Success\n");
return;
}
void init(Serial* ptr)
{
ptr->open = open;
ptr->close = close;
}
int main()
{
Serial serial,serial_2;
serial.init = init;
serial.init(&serial); // Line1
serial_2.init = init;
serial_2.init(&serial_2); // Line2
serial.open();
//rest of code
serial.close();
serial_2.open();
serial_2.close();
return 0;
}
In C, the standard way would be to declare an initializer macro:
#define SERIAL_INITIALIZER { .init = init, .open = open, /* and others */ }
Serial serial = SERIAL_INITIALIZER;
In most cases in C there is simply no need for dynamic intialization of variables. You only need it for malloced objects.
C++ add some automatization by calling constructor/destructor. In pure C is no way to do so. You should do all steps manually: create and initialize object (call constructor-like function for structure), call functions by pointers from the structure instance, call destructor (it should destroy the instance and free related resources).
If is no polymorphism in your task then use simple way - without pointers to functions, but each function (method) should take pointer to the object.
Common case example:
struct MyStruct
{
// data
};
struct MyStruct* createMyStruct(/* maybe some input */)
{
// create, init and return the structure instance
}
void destoyMyStruct(struct MyStruct* obj)
{
// free resources and delete the instance
}
void doSomeAction(struct MyStruct* obj /* , some other data */)
{
// ...
}
int main()
{
struct MyStruct* object = createMyStruct();
doSomeAction(object);
destoyMyStruct(object);
return 0;
}
Edit 1: macro is only for very simple cases and error-prone way.
Typically, you would do this through "opaque type". Meaning that you declare an object of incomplete type in your header:
typedef struct Serial Serial;
And then in the C file, you place the actual struct definition. This will hide the contents of the struct to the caller (private encapsulation). From your constructor, you could then set up private member functions:
struct Serial
{
void(*init)(void);
void(*open)(void);
void(*close)(void);
};
// private member functions:
static void open (void);
...
// constructor:
Serial* SerialCreate (void)
{
Serial* s = malloc(sizeof (*s));
...
s->open = open;
return s;
}
This means that if you wish to inherit the class, you will only need to change the constructor.
Though of course, if you wish to implement true polymorphism, you don't want to change any code. You could solve this by passing the init function as parameter to the constructor.
header file:
typedef void init_func_t (void);
c file:
// constructor:
Serial* SerialCreate (init_func_t* init)
{
Serial* s = malloc(sizeof (*s));
...
init();
return s;
}
And then from the init function in the inherited class, set all private member functions.
I've a huge C project with a module reading and managing configuration data. If I have to add a new configuration parameter, I'll have to edit several functions, e.g. as pseudo-code:
void read_configuration(config *c) {
read_param("p1", c->p1);
read_param("p2", c->p2);
read_param("p3", c->p3);
/* ... */
}
void dump_configuration(config *c) {
dump_param("p1", c->p1);
dump_param("p2", c->p2);
dump_param("p3", c->p3);
/* ... */
}
Is there a way to ensure by macro at compile time, that each location has at least the same count of parameters? I thought of making dump_param some kind of macro counting the invocations and then add something like
#if nr_read != nr_dump
#error "You forgot something, idiot!"
#endif
at the end of the module. I can't find a method to make the macro count its invocations, though...
Since the list of parameters is the same in both functions, how about factoring that out and avoid any possible mismatch ?
Using X-macros
#define X_CONFIG_PARAMS(config) \
X("p1", (config).p1) \
X("p2", (config).p2) \
X("p3", (config).p3)
void read_configuration(config *c) {
#define X(name, param) read_param(name, ¶m);
X_CONFIG_PARAMS(*c)
#undef X
}
void dump_configuration(config *c) {
#define X(name, param) dump_param(name, ¶m);
X_CONFIG_PARAMS(*c)
#undef X
}
Using function pointers
void alter_config(config *c, void(*func)(char const *name, Param *param)) {
func("p1", &c->p1);
func("p2", &c->p2);
func("p3", &c->p3);
}
void read_configuration(config *c) {
alter_config(c, read_param);
}
void dump_configuration(config *c) {
alter_config(c, dump_param);
}
Using an array and offsetof
struct param_info {
char const *name;
size_t config_offs;
};
param_info allParams[] = {
{"p1", offsetof(config, p1)},
{"p2", offsetof(config, p2)},
{"p3", offsetof(config, p3)}
};
void read_configuration(config *c) {
size_t paramCount = sizeof allParams / sizeof *allParams;
for(size_t i = 0; i < paramCount; ++i) {
Param *p = (Param*)((char*)config + allParams[i].config_offs);
read_param(allParams[i].name, p);
}
}
void dump_configuration(config *c) {
size_t paramCount = sizeof allParams / sizeof *allParams;
for(size_t i = 0; i < paramCount; ++i) {
Param *p = (Param*)((char*)config + allParams[i].config_offs);
dump_param(allParams[i].name, p);
}
}
I would rather let the preprocessor write the code in the first place.
It could look something like this:
Define the list of parameters in a separate file, say parameters.inc:
PARAM (p1)
PARAM (p2)
...
Then in the source code locally define the macro PARAM as required and let the preprocessor include and expand the contents of parameters.inc:
void read_configuration(config *c) {
#define PARAM(NAME) read_param(#NAME, c->NAME);
#include "parameters.inc"
#undef PARAM
}
void dump_configuration(config *c) {
#define PARAM(NAME) dump_param(#NAME, c->NAME);
#include "parameters.inc"
#undef PARAM
}
I don't think you can do this at compile time without ugly hacks.
What you could do: add a test to your test suite which replaces the header that contains the read_param() and dump_param() macros so they generate code which only updates a counter. Then, in the main() function of that test, place an assertion that compares both counters and fails if they're not equal.
You do have a test suite and run it at compile time, right? ;-)
However, I do agree with the comment that it's probably better to do this differently. In an approach called "table-driven programming", you turn the macro definition and data definition on their head (that is, you have the #define in your .c file and the use of the macro in the header rather than the other way around), you don't have this problem. Poul-Henning Kamp, of FreeBSD fame, explains very well how to that here.
In my company's code we have general get() and set() methods for interop between certain components. However, if I try to run PREfast I get inundated with warnings because PREfast doesn't realize that the get() method initializes the given parameters.
The problem is that since those methods are very general, they don't simply take a parameter (which I could mark with _Out_ or similar, but an array of structs which holds the data as to which data should be returned.
In code (greatly simplified):
typedef struct
{
int type;
int* data;
} ARGS;
void get(int count, ARGS* args)
{
for (int i = 0; i < count; i++)
*(args[i].data) = 42; // Actually handled by internal methods
}
// Sample Usage
void foo()
{
int value;
ARGS args[1];
args[0].type = 1234;
args[0].data = &value;
get(1, args);
// Do something with value
// PREfast complains that value is uninitialized (error C6001)
printf("%d", value);
}
Is there any way to annotate this so PREfast knows that args.data is initialized by get()? Or is this too complex for PREfast to handle?
EDIT: If I use get(1, &args), then the warning goes away. So there is some heuristic in PREfast which can handle this case, but I haven't found out if it is possible to trigger it externally:
void get2(int count, ARGS(* args)[1]) // Needs the size of args, or it won't compile below
{
for (int i = 0; i < count; i++)
*(*args)[i].data = 42; // Actually handled by internal methods
}
// Sample Usage
void foo2()
{
int value;
ARGS args[1];
args[0].type = 1234;
args[0].data = &value;
get2(1, &args);
// Do something with value
printf("%d", value);
}
This should fix the warning.
void foo()
{
int value=0;
...
}
Note that get() will be called in runtime only. Since, PREfast is a static analysis tool, it might report that the value is uninitialized. Nevertheless, initializing a variable before use is always a best practice in C.
Another way would be to use the PREfast suppress as below:
void foo()
{
int value;
ARGS args[1];
args[0].type = 1234;
args[0].data = &value;
get(1, args);
// Do something with value
// PREfast complains that value is uninitialized (error C6001)
#pragma prefast(suppress:C6001 , "PREfast noise: the variable value will be initialized by get method in a line above")
printf("%d", value);
}
It suppresses the warnings in the next line after the suppress statement.
Also, do add the following code in you header files(or source files) just before using the pragma prefast in your code:
#ifndef _PREFAST_
#pragma warning(disable:4068)
#endif
to avoid 4068 warning to be flagged. NOTE: pragma prefast is an extension to the PREfast AST compiler only and may not be supported by other compilers.
I am working on an embedded application where the device is controlled through a command interface. I mocked the command dispatcher in VC and had it working to my satisfaction; but when I then moved the code over to the embedded environment, I found out that the compiler has a broken implementation of pointer-to-func's.
Here's how I originally implemented the code (in VC):
/* Relevant parts of header file */
typedef struct command {
const char *code;
void *set_dispatcher;
void *get_dispatcher;
const char *_description;
} command_t;
#define COMMAND_ENTRY(label,dispatcher,description) {(const char*)label, &set_##dispatcher, &get_##dispatcher, (const char*)description}
/* Dispatcher data structure in the C file */
const command_t commands[] = {
COMMAND_ENTRY("DH", Dhcp, "DHCP (0=off, 1=on)"),
COMMAND_ENTRY("IP", Ip, "IP Address (192.168.1.205)"),
COMMAND_ENTRY("SM", Subnet, "Subunet Mask (255.255.255.0)"),
COMMAND_ENTRY("DR", DefaultRoute, "Default router (192.168.1.1)"),
COMMAND_ENTRY("UN", Username, "Web username"),
COMMAND_ENTRY("PW", Password, "Web password"),
...
}
/* After matching the received command string to the command "label", the command is dispatched */
if (pc->isGetter)
return ((get_fn_t)(commands[i].get_dispatcher))(pc);
else
return ((set_fn_t)(commands[i].set_dispatcher))(pc);
}
Without the use of function pointers, it seems like my only hope is to use switch()/case statements to call functions. But I'd like to avoid having to manually maintain a large switch() statement.
What I was thinking of doing is moving all the COMMAND_ENTRY lines into a separate include file. Then wraps that include file with varying #define and #undefines. Something like:
/* Create enum's labels */
#define COMMAND_ENTRY(label,dispatcher,description) SET_##dispatcher, GET_##dispatcher
typedef enum command_labels = {
#include "entries.cinc"
DUMMY_ENUM_ENTRY} command_labels_t;
#undefine COMMAND_ENTRY
/* Create command mapping table */
#define COMMAND_ENTRY(label,dispatcher,description) {(const char*)label, SET_##dispatcher, GET_##dispatcher, (const char*)description}
const command_t commands[] = {
#include "entries.cinc"
NULL /* dummy */ };
#undefine COMMAND_ENTRY
/*...*/
int command_dispatcher(command_labels_t dispatcher_id) {
/* Create dispatcher switch statement */
#define COMMAND_ENTRY(label,dispatcher,description) case SET_##dispatcher: return set_##dispatcher(pc); case GET_##dispatcher: return get_##dispatcher(pc);
switch(dispatcher_id) {
#include "entries.cinc"
default:
return NOT_FOUND;
}
#undefine COMMAND_ENTRY
}
Does anyone see a better way to handle this situation? Sadly, 'get another compiler' is not a viable option. :(
--- Edit to add:
Just to clarify, the particular embedded environment is broken in that the compiler is supposed to create a "function-pointer table" which is then used by the compiler to resolve calls to functions through a pointer. Unfortunately, the compiler is broken and doesn't generate a correct function-table.
So I don't have an easy way to extract the func address to invoke it.
--- Edit #2:
Ah, yes, the use of void *(set|get)_dispatcher was my attempt to see if the problem was with the typedefine of the func pointers. Originally, I had
typedef int (*set_fn_t)(cmdContext_t *pCmdCtx);
typedef int (*get_fn_t)(cmdContext_t *pCmdCtx);
typedef struct command {
const char *code;
set_fn_t set_dispatcher;
get_fn_t get_dispatcher;
const char *_description;
} command_t;
You should try changing your struct command so the function pointers have the actual type:
typedef struct command {
const char *code;
set_fn_t set_dispatcher;
get_fn_t get_dispatcher;
const char *_description;
} command_t;
Unfortunately, function pointers are not guaranteed to be able to convert to/from void pointers (that applies only to pointers to objects).
What's the embedded environment?
Given the information posted in the updates to the question, I see that it's really a bugged compiler.
I think that your proposed solution seems pretty reasonable - it's probably similar to what I would have come up with.
A function pointer isn't actually required to fit in a void*. You could check to make sure that the value you're calling is actually the address of the function. If not, use a function pointer type in the struct: either get_fn_t, or IIRC void(*)(void) is guaranteed to be compatible with any function pointer type.
Edit: OK, assuming that calling by value can't be made to work, I can't think of a neater way to do what you need than auto-generating the switch statement. You could maybe use an off-the-shelf ASP-style preprocessor mode for ruby/python/perl/php/whatever prior to the C preprocessor. Something like this:
switch(dispatcher_id) {
<% for c in commands %>
case SET_<% c.dispatcher %>: return set_<% c.dispatcher %>(pc);
case GET_<% c.dispatcher %>: return get_<% c.dispatcher %>(pc);
<% end %>
default:
return NOT_FOUND;
}
might be a bit more readable than the macro/include trick, but introducing a new tool and setting up the makefiles is probably not worth it for such a small amount of code. And the line numbers in the debug info won't relate to the file you think of as the source file unless you do extra work in your preprocessor to specify them.
Can you get the vendor to fix the compiler?
To what extent is the pointer-to-function broken?
If the compiler allows you to get the address of a function (I'm from C++, but &getenv is what I mean), you could wrap the calling convention stuff into assembler.
As said, I'm a C++ssie, but something in the way of
; function call
push [arg1]
push [arg2]
call [command+8] ; at the 4th location, the setter is stored
ret
If even that is broken, you could define an array of extern void* pointers which you define, again, in assembly.
try this syntax:
return (*((get_fn_t)commands[i].get_dispatcher))(pc);
It's been awhile since I've done C & function pointers, but I believe the original C syntax required the * when dereferencing function pointers but most compilers would let you get away without it.
Do you have access to the link map?
If so, maybe you can hack your way around the wonky function-pointer table:
unsigned long addr_get_dhcp = 0x1111111;
unsigned long addr_set_dhcp = 0x2222222; //make these unique numbers.
/* Relevant parts of header file */
typedef struct command {
const char *code;
unsigned long set_dispatcher;
unsigned long get_dispatcher;
const char *_description;
} command_t;
#define COMMAND_ENTRY(label,dispatcher,description) {(const char*)label,
addr_set_##dispatcher, addr_get_##dispatcher, (const char*)description}
Now compile, grab the relevant addresses from the link map, replace the constants, and recompile. Nothing should move, so the map ought to stay the same. (Making the original constants unique should prevent the compiler from collapsing identical values into one storage location. You may need a long long, depending on the architecture)
If the concept works, you could probably add a post-link step running a script to do the replacement automagically. Of course, this is just a theory, it may fail miserably.
Maybe, you need to look into the structure again:
typedef struct command {
const char *code;
void *set_dispatcher; //IMO, it does not look like a function pointer...
void *get_dispatcher; //more like a pointer to void
const char *_description;
} command_t;
Let say your dispatchers have the following similar function definition:
//a function pointer type definition
typedef int (*genericDispatcher)(int data);
Assume that the dispatchers are like below:
int set_DhcpDispatcher(int data) { return data; }
int get_DhcpDispatcher(int data) { return 2*data; }
So, the revised structure will be:
typedef struct command {
const char *code;
genericDispatcher set_dispatcher;
genericDispatcher get_dispatcher;
const char *_description;
} command_t;
Your macro will be:
#define COMMAND_ENTRY(label,dispatcher,description) \
{ (const char*)label, \
set_##dispatcher##Dispatcher, \
get_##dispatcher##Dispatcher, \
(const char*)description }
Then, you can set your array as usual:
int main(int argc, char **argv)
{
int value1 = 0, value2 = 0;
const command_t commands[] = {
COMMAND_ENTRY("DH", Dhcp, "DHCP (0=off, 1=on)")
};
value1 = commands[0].set_dispatcher(1);
value2 = commands[0].get_dispatcher(2);
printf("value1 = %d, value2 = %d", value1, value2);
return 0;
}
Correct me, if I am wrong somewhere... ;)