big struct init in C - c

I have got a choice to do to initialize a big structure in C.
I am working on an embedded micro with a tiny memory size.
I've got the chip configuration saved in EEPROM.
So I have a struct which contain all the configuration page in EEPROM :
Typedef struct
{
unsigned int Param1;
float Param2;
unsigned char Param3;
[...]
char Paramx[SIZE];
} T_EEPROM;
We have to keep in mind that this struct is heavy regarding the tiny memory size of the micro.
I have a global variable of this type :
T_EEPROM MyConfig;
This is used to modify or access EEPROM configuration :
MyConfig.Param1 = NewValue;
WriteEEPROM(MyConfig);
Now I want to initialize this variable with diffrents kind of factory configurations (CONFIG A, CONFIG B, etc)
All the parameters for each factory configuration can be defined by a #define
After that, I don't know which method to use :
1) Write an initialization function which take all the values in parameters :
bool InitEEPROM(unsigned int param1, float param2, unsigned char param3, [...], char *Paramx)
{
MyConfig.Param1 = param1;
MyConfig.Param2 = param2;
MyConfig.Param3 = param3;
[...]
MyConfig.Paramx = paramx;
}
After, I could call the function lake that :
void InitFactoryEEPROM (unsigned char type)
{
if (type == 1)
InitEEPROM(DEFINE_PARAM1_CONFIG_1, DEFINE_PARAM2_CONFIG_1,DEFINE_PARAM3_CONFIG_1, [...], DEFINE_PARAMx_CONFIG_1);
else if (type == 2)
InitEEPROM(DEFINE_PARAM1_CONFIG_2, DEFINE_PARAM2_CONFIG_2,DEFINE_PARAM3_CONFIG_2, [...], DEFINE_PARAMx_CONFIG_2);
else if (type == 3)
[...]
}
Disadventage: heavy to write
2) Create a big array with all the factory configurations :
T_EEPROM FactoryEepromConfig[CONFIG_COUNT] =
{
{DEFINE_PARAM1_CONFIG_1, DEFINE_PARAM2_CONFIG_1, DEFINE_PARAM3_CONFIG_1, [...], DEFINE_PARAMx_CONFIG_1},
{DEFINE_PARAM1_CONFIG_2, DEFINE_PARAM2_CONFIG_2,DEFINE_PARAM3_CONFIG_2, [...], DEFINE_PARAMx_CONFIG_2},
[...]
};
With an easier initialisation function:
bool InitEEPROM(T_EEPROM factoryConfig)
{
MyConfig.Param1 = factoryConfig.Param1 ;
MyConfig.Param2 = factoryConfig.Param2;
MyConfig.Param3 = factoryConfig.Param3;
[...]
MyConfig.Paramx = factoryConfig.Paramx;
}
And this call:
void InitFactoryEEPROM (unsigned char type)
{
InitEEPROM(FactoryEepromConfig[type]);
}
Disadventage:
Very heavy in memory because I have a T_EEPROM instance for each factory configuration.
Anyone has got a better idea?

In all the scenario's (possibilities) you gave, the values need to be in memory, either as variables or as values to initialize variables with. So there is not much difference in the memory footprint. Using initialization functions has the overhead of code bytes required to execute the initialization.
Having one static array containing all the values, and that you index every time you need a value, has the overhead of instructions to index the array. Copying the values of an array index to a "working set" variable has the overhead of the extra variable.
Possibly you can measure which is smallest by making several versions, e.g.:
one static array that is indexed for each parameter access;
one static array and copying the working set to an extra variable;
initializing a working set variable using an initialization function.
But this assumes the working set of values can change during execution. If they don;t change, then you can use #defines to select the working set of values and use that for static initialization of the working set variables.

This is short and clean:
static const T_EEPROM FactoryEepromConfig[CONFIG_COUNT] =
{
{DEFINE_PARAM1_CONFIG_1, DEFINE_PARAM2_CONFIG_1, DEFINE_PARAM3_CONFIG_1, [...], DEFINE_PARAMx_CONFIG_1},
{DEFINE_PARAM1_CONFIG_2, DEFINE_PARAM2_CONFIG_2,DEFINE_PARAM3_CONFIG_2, [...], DEFINE_PARAMx_CONFIG_2},
[...]
};
void InitFactoryEEPROM (size_t type)
{
assert(type < CONFIG_COUNT);
MyConfig = FactoryEepromConfig[type];
}
to avoid globals you can change the function to this:
void InitFactoryEEPROM (T_EEPROM* config, size_t type)
{
assert(type < CONFIG_COUNT);
*config = FactoryEepromConfig[type];
}

Related

Accessing label address outside of function

I'm writing "threaded interpreter" using computed goto. How do I initialize address lookup table to be visible from different functions without additional runtime cost?
Label address is only visible at same function and static lookup table is initialized by compiler in data section without runtime cost at each call. But it's visible only in same function and I want to have another function to have access to it, for example to cache addresses and save lookups in main interpreter code. I can take pointer to this table and store it somewhere, but it will happen every time function is called, and it will get called frequently. Yes, it's just only one mov, but is there another way?
#include <stdio.h>
static void** table_ptr;
// how do i declare static variable and init it later once?
// Tried this. Generates runtime assigns at each call. Not unexpected
// static void** jumps_addr;
int main()
{
// labels are visible only inside the function
// generates runtime assigns at each call
// jumps_addr = (void* [10]){
// this initializes it in static data section, but name is only visible inside this function
static void* jumps_addr[10] = {
[1] = &&operation_print,
};
// want another way instead of this
table_ptr = jumps_addr;
// not optimize this
volatile int opcode = 1;
goto *jumps_addr[opcode];
return 0;
operation_print:;
printf("hello\n");
return 0;
}
void do_some_preprocessing_work(void){
// want access to jumps_addr table here
// without having to store it somewhere
// [do something with table_ptr]
// this is to prevent optimization to explore what compiler does on godbolt.org
// because it will optimize away table_ptr entirely if not used
volatile i = 1;
i += table_ptr[i];
//actual code here will store labbel addrs into opcode struct to save table lookup at runtime
}
The solution might sound unorthodox, but how about not to use any functions, but only goto.
Like so:
#include <stdio.h>
int main()
{
volatile int opcode;
static void* jumps_addr[10] = {
[0] = &&do_some_preprocessing_work,
[1] = &&operation_print
};
opcode = 0;
goto *jumps_addr[opcode];
return 1;
operation_print:
printf("hello\n");
return 0;
do_some_preprocessing_work:
printf("jumps_addr[%i]\n", ++opcode);
goto *jumps_addr[opcode];
return 1;
}

How to avoid globals in EEPROM structs for system settings?

I'm struggling with getting system settings from EEPROM and trying to avoid having them as global variables and wondered what the prevailing wisdom is and if there's an accepted practice and / or elegant solution.
I'm getting system settings stored in an EEPROM via structures with some error checking and the sizeof operator in main.c along the lines of:
// EEPROM data structures
typedef struct system_tag
{
uint8_t buzzer_volume;
uint8_t led_brightness;
uint8_t data_field_3;
} system_t;
typedef struct counters_tag
{
uint16_t counter_1;
uint16_t counter_2;
uint16_t counter_3;
} counters_t;
typedef struct eeprom_tag
{
system_t system_data;
uint8_t system_crc;
counters_t counters;
uint8_t counters_crc;
} eeprom_t;
// Default values
static system_t system_data =
{
.buzzer_volume = 50,
.led_brightness = 50,
.data_field_3 = 30
};
static counters_t counter =
{
.counter_1 = 0,
.counter_2 = 0,
.counter_3 = 0
};
// Get system settings data from the EEPROM
if (EEPROM_check_ok(EEPROM_BASE_ADDRESS, sizeof(system_t)))
{
eeprom_read_block(&system_data, (uint16_t *) EEPROM_BASE_ADDRESS, sizeof(system_t));
}
if (EEPROM_check_ok((EEPROM_BASE_ADDRESS + offsetof(eeprom_t, counters)), sizeof(counters_t)))
{
eeprom_read_block(&counter, (uint16_t *) EEPROM_BASE_ADDRESS, sizeof(counters_t));
}
I'm then using the system settings data at the moment to set other variables in different modules. E.g. in another file, buzzer.c, I have a module static variable (in an effort to avoid globals) with accessor functions to try and give some encapsulation:
// Current volume setting of the buzzer
static uint8_t volume = 50;
void BUZZER_volume_set(uint8_t new_volume)
{
volume = new_volume;
}
uint8_t BUZZER_volume_get(void)
{
return (volume);
}
The problem I feel is I've now got unnecessary duplication of data, as when I pass the buzzer_volume from the system data to set the static volume variable in the buzzer module things could get out of synchronisation. Having the system settings as globals would be easy, but I know this is frowned upon.
Is there a more elegant way of doing this without using globals and still having some encapsulation?
Any suggestions would be gratefully received.
General advice to avoiding globals (and why you need to do so) are given in Jack Ganssle's excelent article "A Pox on Globals". Essential reading.
One solution is simply to have accessor functions in main.c (or better a separate nvdata.c, to protect it from direct access by anything).
Rather then relying on a single initialisation function being called before any access to the data, I would suggest an "initialise on first use" semantic thus:
const system_t* getSystemData()
{
static bool initialised = false ;
if( !initialised )
{
eeprom_read_block( &system_data,
(uint16_t*)EEPROM_BASE_ADDRESS,
sizeof(system_t) ) ;
initialised = true ;
}
return &system_data ;
}
void setSystemData( const system_t* new_system_data )
{
system_data = *new_system_data ;
eeprom_write_block( &system_data,
(uint16_t*)EEPROM_BASE_ADDRESS,
sizeof(system_t));
}
Then in buzzer.c:
uint8_t BUZZER_volume_get(void)
{
return getSystemData()->buzzer_volume ;
}
void BUZZER_volume_set( uint8_t new_volume )
{
system_t new_system_data = *getSystemData() ;
new_system_data.buzzer_volume = new_volume ;
setSystemData( &new_system_data ) ;
}
There are some issues with this - such as if your structures are large updating a single member can be expensive. That could be resolved however, but may not be an issue in your application.
Another issue is the writing back to the EEPROM on every change - that may cause unnecessary thrashing of the EEPROM and stall your program for significant periods if you have several sequential changes to the same structure. In that case a simple method is to have a separate commit operation:
void setSystemData( const system_t* new_system_data )
{
system_data = *new_system_data ;
system_data_commit_pending = true ;
}
void commitSystemData()
{
if( system_data_commit_pending )
{
eeprom_write_block( &system_data,
(uint16_t*)EEPROM_BASE_ADDRESS,
sizeof(system_t));
}
}
where you commit the data only when necessary or safe to do so - such as on a controlled shutdown or explicitly selected UI "save settings" operation for example.
A more sophisticated method is to set a timer on change and have the commit function called when the timer expires, each "set" would restart the timer, so the commit would only occur in "quiet" periods. This method is especially suited to a multi-threaded solution.

Update global C struct using only one function without passing whole data structure

I am developing a database access layer to store data of software subsystems. The database interface has two functions, database_get() and database_set(). They take two arguments, first is a ID that identifies the software component and the second argument is a typedef struct that holds the new settings for this software component. Then i have:
#define COMPONENT1_ID 7
typedef struct
{
int member1;
char member2;
char member3;
} COMPONENT1_STRUCT_T ;
I can store and retrieve persistent data calling the database_set(COMPONENT1_ID, (void *) &new_struct) and database_get(COMPONENT1_ID, (void *) &new_struct) functions. It works the same for storing data from any other software subsystem using this database.
Now i am developing APIs to manage this software subsystems. This APIs are used by the user interfaces. The API of a software subsystem is taking care of performing all the logic behind the component and also calling the database to make its data persistent. I have developed a function for the API which carries out the operation and finally call a function like this:
int save_new_member1_db(int member1);
{
COMPONENT1_STRUCT_T new_setting;
database_get(COMPONENT1_ID, (void *)&new_setting);
new_setting.member1 = member1;
database_set(COMPONENT1_ID, (void *)&new_setting);
}
I wonder if i can avoid creating a new function to update each member data in the database.
Also I dont want a big function taking the whole struct or all members of the struct if it means the subsystem API gets reduced to one function. The subsystem can be a LED display and its API could be different methods doing one thing as update_led_display_color(const LED_DISPLAY_COLOR new color), update_led_display_font(const LED_DISPLAY_FONT cur_font), get_led_display_font(LED_DISPLAY_FONT *cur_font) ...
You are going to need some kind of mapping between a symbolic constant representing a member and information you need to set that member. You could use something like your "COMPONENT1_ID" for each member and have an array of size+offset information for each member like so:
#include <stdio.h>
#include <stddef.h>
#include <string.h>
// in header file (or wherever so that it is visible to
// the definition of "Test_save_member" and not a part of
// the subsystem API)
#define TEST_ID 7
// in a c file (in your database implementation, I assume)
typedef struct
{
int mem1;
char mem2;
char mem3;
} Test;
// for sure in header file exposed in your subsystem API
typedef enum
{
MEM1,
MEM2,
MEM3,
NUM_MEMBERS
} TestMember;
// in c file (in your database implementation, I assume again)
typedef struct
{
size_t offset;
size_t size;
} MemberInfo;
static MemberInfo member_info[NUM_MEMBERS] =
{
{ offsetof(Test, mem1), sizeof(int) },
{ offsetof(Test, mem2), sizeof(char) },
{ offsetof(Test, mem3), sizeof(char) }
};
// also a part of your subsystem API
int Test_save_member(TestMember member, void* value)
{
if (!value || member < 0 || member >= NUM_MEMBERS))
return 0;
Test new_setting;
database_get(TEST_ID, (void *)&new_setting);
MemberInfo info = member_info[member];
memcpy((char*)(&new_setting) + info.offset, value, info.size);
database_set(TEST_ID, (void *)&new_setting);
return 1;
}
// subsystem API usage
int main(void)
{
int new_mem1 = 5;
Test_save_member(MEM1, &new_mem1);
return 0;
}
Depending upon whether you want to edit your database functions, the amount of coupling you want to deal with, etc, this could change drastically; I don't think, however, that you can get away without some type of mapping given the constraints you mentioned.
This particular implementation would disallow passing literals, but that shouldn't be too big of an issue (to deal with or work around).

How avoid using global variable when using nftw

I want to use nftw to traverse a directory structure in C.
However, given what I want to do, I don't see a way around using a global variable.
The textbook examples of using (n)ftw all involve doing something like printing out a filename. I want, instead, to take the pathname and file checksum and place those in a data structure. But I don't see a good way to do that, given the limits on what can be passed to nftw.
The solution I'm using involves a global variable. The function called by nftw can then access that variable and add the required data.
Is there any reasonable way to do this without using a global variable?
Here's the exchange in previous post on stackoverflow in which someone suggested I post this as a follow-up.
Using ftw can be really, really bad. Internally it will save the the function pointer that you use, if another thread then does something else it will overwrite the function pointer.
Horror scenario:
thread 1: count billions of files
thread 2: delete some files
thread 1: ---oops, it is now deleting billions of
files instead of counting them.
In short. You are better off using fts_open.
If you still want to use nftw then my suggestion is to put the "global" type in a namespace and mark it as "thread_local". You should be able to adjust this to your needs.
/* in some cpp file */
namespace {
thread_local size_t gTotalBytes{0}; // thread local makes this thread safe
int GetSize(const char* path, const struct stat* statPtr, int currentFlag, struct FTW* internalFtwUsage) {
gTotalBytes+= statPtr->st_size;
return 0; //ntfw continues
}
} // namespace
size_t RecursiveFolderDiskUsed(const std::string& startPath) {
const int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
const int maxFileDescriptorsToUse = 1024; // or whatever
const int result = nftw(startPath.c_str(), GetSize, maxFileDescriptorsToUse , flags);
// log or something if result== -1
return gTotalBytes;
}
No. nftw doesn't offer any user parameter that could be passed to the function, so you have to use global (or static) variables in C.
GCC offers an extension "nested function" which should capture the variables of their enclosing scopes, so they could be used like this:
void f()
{
int i = 0;
int fn(const char *,
const struct stat *, int, struct FTW *) {
i++;
return 0;
};
nftw("path", fn, 10, 0);
}
The data is best given static linkage (i.e. file-scope) in a separate module that includes only functions required to access the data, including the function passed to nftw(). That way the data is not visible globally and all access is controlled. It may be that the function that calls ntfw() is also part of this module, enabling the function passed to nftw() to also be static, and thus invisible externally.
In other words, you should do what you are probably doing already, but use separate compilation and static linkage judiciously to make the data only visible via access functions. Data with static linkage is accessible by any function within the same translation unit, and you avoid the problems associated with global variables by only including functions in that translation unit that are creators, maintainers or accessors of that data.
The general pattern is:
datamodule.h
#if defined DATAMODULE_INCLUDE
<type> create_data( <args>) ;
<type> get_data( <args> ) ;
#endif
datamodule.c
#include "datamodule.h"
static <type> my_data ;
static int nftwfunc(const char *filename, const struct stat *statptr, int fileflags, struct FTW *pfwt)
{
// update/add to my_data
...
}
<type> create_data( const char* path, <other args>)
{
...
ret = nftw( path, nftwfunc, fd_limit, flags);
...
}
<type> get_data( <args> )
{
// Get requested data from my_data and return it to caller
}

How do I write a dispatcher, if my compiler's support for pointers-to-functions is broken?

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... ;)

Resources