Source analysis iw (.handler = (_handler),) - c

This question already has answers here:
What does a dot before the variable name in struct mean?
(2 answers)
Closed 7 hours ago.
I'm reading the source code iw and
I'm stucked in this struct.
I dont't understand what these code mean? (.handler = (_handler), etc...)
How can I understand that or any documents to learn that.
static struct cmd \
__cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden = {\
.name = (_name), \
.args = (_args), \
.cmd = (_nlcmd), \
.nl_msg_flags = (_flags), \
.hidden = (_hidden), \
.idby = (_idby), \
.handler = (_handler), \
.help = (_help), \
.parent = _section, \
.selector = (_sel), \
}; \

This is a macro that unfolds in a static structure.
#define __COMMAND(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help, _sel)\
static struct cmd \
__cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden\
__attribute__((used)) __attribute__((section("__cmd"))) = { \
.name = (_name), \
.args = (_args), \
.cmd = (_nlcmd), \
.nl_msg_flags = (_flags), \
.hidden = (_hidden), \
.idby = (_idby), \
.handler = (_handler), \
.help = (_help), \
.parent = _section, \
.selector = (_sel), \
}
If you take a look at the definition of cmd struct from iw/iw.h file, you would see that the handler member is a function pointer taking a whole bunch of parameters and returning int.
struct cmd {
const char *name;
const char *args;
const char *help;
const enum nl80211_commands cmd;
int nl_msg_flags;
int hidden;
const enum command_identify_by idby;
/*
* The handler should return a negative error code,
* zero on success, 1 if the arguments were wrong
* and the usage message should and 2 otherwise.
*/
int (*handler)(struct nl80211_state *state,
struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id);
const struct cmd *(*selector)(int argc, char **argv);
const struct cmd *parent;
};
The macro initializes the struct assigning the provided function address to this pointer. The handler member now can be used as sort of interface for the struct and one may call the provided function via it.

Related

Defining a struct along with a str dictionary using a macro

I am trying to automatise the generation of struct in my code for which the syntax is specify by the Midas Library. The difficulty here lies in the parallel building of const char* dictionary that mimic the struct definition:
typedef struct {
BOOL runColdStartScript;
BOOL runPedestalScript;
BOOL triggerCommunicationTest;
BOOL updateOdbParameters;
BOOL runCmdBuffer;
BOOL runSelectedScript;
} myHotLink;
myHotLink hotLinkContainer{};
const char *hot_links_str[9] = { \
"[.]", \
"runColdStartScript = BOOL : n", \
"runPedestalScript = BOOL : n", \
"triggerCommunicationTest = BOOL : n", \
"updateOdbParameters = BOOL : n", \
"runCmdBuffer = BOOL : n", \
"runSelectedScript = BOOL : n", \
"", nullptr
};
Ideally I'd like to generate this piece of code with a macro. For example:
MAKE_HOT_LINK(
myHotLink,
{ BOOL, runColdStartScript, n },
{ BOOL, runPedestalScript, n },
...
)
Does someone have an idea on how to define (and properly call) the MAKE_HOT_LINK macro?
Cheers!
You could use some metamacros to define the fields you want and some other macros that expand those to the declaration and descriptor:
#define MYHOTLINK_FIELDS(M) \
M(BOOL, runColdStartScript, n) \
M(BOOL, runPedestalScript, n) \
M(BOOL, triggerCommunicationTest, n) \
M(BOOL, updateOdbParameters, n) \
M(BOOL, runCmdBuffer, n) \
M(BOOL, runSelectedScript, n) \
#define FIELD_DECL(TYPE, NAME, TAG) TYPE NAME;
#define FIELD_DESCRIPTOR(TYPE, NAME, TAG) #NAME " = " #TYPE " : " #TAG,
#define DECLARE_STRUCT(STYPE) struct { STYPE(FIELD_DECL) }
#define STRUCT_DESCRIPTOR(STYPE) { "[.]", STYPE(FIELD_DESCRIPTOR) "", nullptr }
typedef DECLARE_STRUCT(MYHOTLINK_FIELDS) myHotLink;
myHotLink hotLinkContainer {};
const char *hot_links_str[] = STRUCT_DESCRIPTOR(MYHOTLINK_FIELDS);
would expand to (equivalent of) what you have above.

meet "called object is not a function" error when use macro to Initialization tree data

I want to implement the Lisp Cons type in C, so I use link list to achieve it.
At the same time, I use a lot of macros to simpilfy the data creation.
The code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Macro Utils
*/
#define create_m(type) ((type *) malloc(sizeof(type)))
#define new_m(type, ...) ({ \
type * __t = create_m(type); \
*__t = (type){ __VA_ARGS__ }; \
__t; })
/*
* Type Define
*/
typedef struct atom Atom;
enum ATOM_TYPES;
// Cons Type
typedef Atom * Cons[2];
#define car(c) (c[0])
#define cdr(c) (c[1])
#define new_cons_m(car, cdr) ({ \
Cons * __c = create_m(Cons); \
car(__c) = car; \
cdr(__c) = cdr; })
// Id Type
typedef char * Id;
#define new_id_m(id) (strdup(id))
// Container Type
enum ATOM_TYPES {
ATOM_CONS, ATOM_ID
};
struct atom {
enum ATOM_TYPES type;
union {
Cons value_cons;
Id value_id;
void * value;
};
};
#define new_atom_m(t, ...) (new_m(Atom, .type = t, __VA_ARGS__))
#define new_atom_cons_m(car, cdr) ( \
new_atom_m(ATOM_CONS, .value_cons = new_cons_m(car, cdr)) )
#define new_atom_id_m(id) ( \
new_atom_m(ATOM_CONS, .value_id = new_id_m(id)) )
int main() {
printf("start program\n");
Atom * test = new_atom_cons_m(
new_atom_id_m("lisp"),
new_atom_cons_m(
new_atom_id_m("log"),
new_atom_id_m("say hello")
)
);
return 0;
}
And it failed to compile, with the following log:
arane.c: In function ‘main’:
arane.c:16:27: error: called object is not a function or function pointer
#define new_m(type, ...) ({ \
^
arane.c:18:18: note: in definition of macro ‘new_m’
*__t = (type){ __VA_ARGS__ }; \
^~~~~~~~~~~
arane.c:68:3: note: in expansion of macro ‘new_atom_m’
new_atom_m(ATOM_CONS, .value_cons = new_cons_m(car, cdr)) )
^~~~~~~~~~
arane.c:68:39: note: in expansion of macro ‘new_cons_m’
new_atom_m(ATOM_CONS, .value_cons = new_cons_m(car, cdr)) )
^~~~~~~~~~
arane.c:92:17: note: in expansion of macro ‘new_atom_cons_m’
Atom * test = new_atom_cons_m(
^~~~~~~~~~~~~~~
arane.c:66:29: note: in expansion of macro ‘new_m’
#define new_atom_m(t, ...) (new_m(Atom, .type = t, __VA_ARGS__))
^~~~~
arane.c:70:3: note: in expansion of macro ‘new_atom_m’
new_atom_m(ATOM_CONS, .value_id = new_id_m(id)) )
^~~~~~~~~~
arane.c:93:5: note: in expansion of macro ‘new_atom_id_m’
new_atom_id_m("lisp"),
^~~~~~~~~~~~~
...and much more errors
I think it is because there are some expressions in function call's argument list. I am seeking for some way to solve it, I use gcc7.5 to finish my work, if needed, I can upgrade it.
-----------2022-01-24-14:15-----------
The problem is solved, with some twest in code, however, I still don't really understand how it was happend.
The code changed as below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Macro Utils
*/
#define create_m(type) ((type *) malloc(sizeof(type)))
#define new_m(type, ...) ({ \
type * __t = create_m(type); \
*__t = (type){ __VA_ARGS__ }; \
__t; })
/*
* Type Define
*/
typedef struct atom Atom;
enum ATOM_TYPES;
// Cons Type
typedef Atom * Cons[2];
#define car(c) (c[0])
#define cdr(c) (c[1]) // deletes here
// Id Type
typedef char * Id;
#define new_id_m(id) (strdup(id))
// Container Type
enum ATOM_TYPES {
ATOM_CONS, ATOM_ID
};
struct atom {
enum ATOM_TYPES type;
union {
Cons value_cons;
Id value_id;
void * value;
};
};
#define new_atom_m(t, ...) (new_m(Atom, .type = t, __VA_ARGS__))
#define new_atom_cons_m(car, cdr) ( \
new_atom_m(ATOM_CONS, .value_cons[0] = car, .value_cons[1] = cdr) )
#define new_atom_id_m(id) ( \ // changes here
new_atom_m(ATOM_CONS, .value_id = new_id_m(id)) )
int main() {
printf("start program\n");
Atom * test = new_atom_cons_m(
new_atom_id_m("lisp"),
new_atom_cons_m(
new_atom_id_m("log"),
new_atom_id_m("say hello")
)
);
// Atom * test = new_atom_cons_m(NULL, NULL);
return 0;
}

Interface for a common data structure

Let's say I have Stack that I want to use to store various different types. If I define the interface as follows:
// stack.h
typedef struct Stack {
size
push // function pointers
pop
etc.
};
And let's say I want to support two different stack types, and so I create:
// stack.c
Stack person_stack;
person_stack->push = push_to_person_stack;
Stack animal_stack;
animal_stack->push = push_to_animal_stack;
How can I make it such that the push_to_<type>_stack is effectively private and the caller of that stack is only able to see the Stack->push function? Or maybe that's not possible in C and you need an OO language to do it, but what would be an example of having a unified interface for this?
You can use function pointers to emulate methods in other OOP languages but still you need to pass the instance to the method otherwise there is no way to know on which stack to push. Also using void* would make more problems than it solves.
struct Stack {
void (*push)(Stack* self, void* data); //< self here
}
Here is a way that I use to emulate template/generics in c by using macros (reference : https://github.com/wren-lang/wren/blob/main/src/vm/wren_utils.h#L16)
#define DECLARE_STACK(type) \
typedef struct { \
type* data; \
int size; \
int capacity; \
} type##Stack; \
void type##Stack_push(type##Stack* self, type value); \
type type##Stack_pop(type##Stack* self); \
void type##Stack_init(type##Stack* self); \
#define DEFINE_STACK(type) \
void type##Stack_push(type##Stack* self, type value) { \
if (self->capacity <= self->size + 1) { \
self->capacity = self->capacity * 2; \
self->data = realloc(self->data, sizeof(type) * self->capacity); \
} \
self->data[self->size] = value; \
self->size++; \
} \
\
type type##Stack_pop(type##Stack* self) { \
self->size--; \
return self->data[self->size]; \
} \
\
void type##Stack_init(type##Stack* self) { \
self->size = 0; \
self->capacity = 2; \
self->data = malloc(sizeof(type) * self->capacity); \
} \
typedef struct Person {
int id;
} Person;
DECLARE_STACK(Person); // in person.h
DEFINE_STACK(Person); // in person.c
int main() {
Person p1, p2, p3, p4;
p1.id = 1; p2.id = 2; p3.id = 3; p4.id = 4;
PersonStack stack;
PersonStack_init(&stack);
PersonStack_push(&stack, p1);
PersonStack_push(&stack, p2);
PersonStack_push(&stack, p3);
Person p;
p = PersonStack_pop(&stack); // p.id = 3
p = PersonStack_pop(&stack); // p.id = 2
PersonStack_push(&stack, p4);
p = PersonStack_pop(&stack); // p.id = 4
p = PersonStack_pop(&stack); // p.id = 1
return 0;
}
And If you want to debug, macros are harder to debug the flow with a debugger, so I've used a python script to generate the expansion of the macro to source and header files before compile (I build with scons which is python based so I automated the source files generation)

Generate multiple similar functions with C preprocessor

I want to generate multiple similar functions replacing just one word across the function.
As an example, for each of the below:
OBJECT = customer
OBJECT = account
use the function template:
void add_OBJECT_to_array(void* item_ptr, int pos)
{
mtx_lock(&OBJECT_array_mtx);
OBJECT_array[pos] = *(OBJECT_t*)item_ptr;
mtx_unlock(&OBJECT_array_mtx);
return;
}
So that I can call
add_order_to_array(ord, 1);
add_customer_to_array(cust, 1);
Is this possible?
Totally possible. You just need to know about the preprocessor concatenation operator ##. The following code will generate two functions add_order_to_array and add_customer_to_array.
#define GENERATE_FUNC(OBJECT) \
void add_ ## OBJECT ## _to_array(void* item_ptr, int pos)\
{ \
mtx_lock(&OBJECT ## _array_mtx); \
OBJECT ## _array[pos] = *(OBJECT ## _t*)item_ptr; \
mtx_unlock(&OBJECT ## _array_mtx); \
return; \
}
GENERATE_FUNC(order)
GENERATE_FUNC(customer)
The preprocessor output will be (unfortunately it does not respect formatting):
void add_order_to_array(void* item_ptr, int pos) { mtx_lock(&order_array_mtx); order_array[pos] = *(order_t*)item_ptr; mtx_unlock(&order_array_mtx); return; }
void add_customer_to_array(void* item_ptr, int pos) { mtx_lock(&customer_array_mtx); customer_array[pos] = *(customer_t*)item_ptr; mtx_unlock(&customer_array_mtx); return; }
Yes it's possible:
#define DECLARE_ADD_FUNCTION(__obj) \
void add_##__obj##_to_array(void* item_ptr, int pos) \
{ \
mtx_lock(&__obj##_array_mtx); \
__obj##_array[pos] = *(__obj##_t*)item_ptr; \
mtx_unlock(&__obj##_array_mtx); \
return; \
}
DECLARE_ADD_FUNCTION(customer)
DECLARE_ADD_FUNCTION(account)
When you look at the output of the preprocessor you get:
gcc -E foo.c
void add_customer_to_array(void* item_ptr, int pos) { mtx_lock(&customer_array_mtx); customer_array[pos] = *(customer_t*)item_ptr; mtx_unlock(&customer_array_mtx); return; }
void add_account_to_array(void* item_ptr, int pos) { mtx_lock(&account_array_mtx); account_array[pos] = *(account_t*)item_ptr; mtx_unlock(&account_array_mtx); return; }
You can even ensure that the pointer type is the correct type by changing the function prototype to add_##__obj##_to_array(__obj##_t *, int pos)

Escape struct field in a macro definition

I have the following structure (simplified):
struct error_t{
const char *file;
const char *error_desc;
};
I wrote a macro to create the structure
#define ERROR_SET(error_desc) \
{ \
struct error_t tmp = {.error_desc = error_desc, .file = __FILE__}; \
struct error_t *ptr = malloc(sizeof(*ptr)); \
memcpy(ptr, &tmp, sizeof(tmp)); \
*error_ptr = ptr; \
}
The problem is that at the line
struct error_t tmp = {.error_desc = error_desc, .file = __FILE__}
both error_descs .error_desc = error_desc are replaced which is not what I wanted. The only solution I can see is to rename the macro function parameter from error_desc to _error_desc, but maybe there is a better way. Maybe we can sort of "escape" the error_desc to be substituted in the .error_desc?
Just do not use the same name for the parameter and the struct member
You can have a different MACRO that the preprocessor would replace as error_desc.
#define ERROR_DESC error_desc
Then you can define ERROR_SET like this:
#define ERROR_SET(error_desc) \
{ \
struct error_t tmp = {.ERROR_DESC = error_desc, .file = __FILE__}; \
struct error_t *ptr = malloc(sizeof(*ptr)); \
memcpy(ptr, &tmp, sizeof(tmp)); \
*error_ptr = ptr; \
}
This works because the substitution is done only once.
You can "deceive" the preprocessor with something like
#define CONCAT(a, b) a##b
#define ERROR_SET(error_desc) \
{ \
struct error_t tmp = { .CONCAT(error,_desc) = error_desc, .file = __FILE__ }; \
...\
}
but it is just not worth it. Just rename the parameter. And develop a convention for parameter naming that would help you to avoid such naming conflicts in the future.
On the second thought, the extra CONCAT macro is not even necessary. This will achieve the same objective
#define ERROR_SET(error_desc) \
{ \
struct error_t tmp = { .error##_desc = error_desc, .file = __FILE__ }; \
...\
}

Resources