I would like to run the function pointed by my struct with auto-filling functionality.
This is the part that I'm working on:
#include <stdio.h>
#include <stdlib.h>
struct Fra { //Fraction
int n; //Numerator
int d; //Denominator
void (*p)(struct Fra*);
void (*sD)(int, struct Fra*);
void (*sN)(int, struct Fra*);
};
void print(struct Fra*);
void setDenom(int, struct Fra*);
void setNum(int, struct Fra*);
int main() {
struct Fra* fraA = 0;
fraA = (struct Fra*) malloc(sizeof(struct Fra));
fraA->sN = setNum;
fraA->sN(2, fraA);
fraA->sD = setDenom;
fraA->sD(3, fraA);
fraA->p = print;
fraA->p(fraA);
return 0;
}
And this is what I've been trying to achieve
From:
fraA->sN(2, fraA);
fraA->sD(3, fraA);
fraA->p(fraA);
To:
fraA->sN(2);
fraA->sD(3);
fraA->p();
After spending some time on trial-error, I've arrived to the conclusion that I need assistance on this. I've tried browsing, but it seems I don't have the right keyword, so I'm unable to verify whether this question is a double or not.
Thanks for any help.
You could declare some macros to savely always pass the correct reference, that's all you can do:
#define FRA_NEW(this, sN sD, sP) \
{ \
(this) = calloc(sizeof(*(this))) \
if (this) \
{ \
(this)->sN = (sN); \
(this)->sN = (sD); \
(this)->sN = (sP); \
} \
}
#define FR_DELETE(this) \
free(this)
#define FRA_PRINT(this) \
(this)->print(this)
#define FRA_SETNUM(this, num) \
(this)->setNum(this, num)
#define FRA_SETDENOM(this, denom) \
(this)->setDenom(this, denom)
Also I'd propose to have "this" always as first parameter to the "member"-functions.
int main(void)
{
struct Fra * fraA = NULL;
FRA_NEW(fraA, setNum, setDenom, print);
if (NULL == fraA)
{
perror("FRA_NEW() failed");
return 1;
}
FRA_SETNUM(fraA, 2);
FRA_SETDENOM(fraA, 3);
FRA_PRINT(fraA);
FRA_DELETE(fraA);
return 0;
}
The only really useful way I can think of would be to provide functions which do the job:
void call_print(struct Fra* fra)
{
fra->p(fra);
}
void call_setDenom(int val, struct Fra* fra)
{
fra->sD(val, fra);
}
void call_setNum(int val, struct Fra* fra);
{
fra->sN(val, fra);
}
and use these:
call_setNum(2, fraA);
call_setDenom(3, fraA);
call_print(fraA);
Related
I am browsing through telegram-cli source code to make some changes. However, I am stuck at a syntax that I am not able to understand.
#define user_cmp(a,b) (tgl_get_peer_id ((a)->id) - tgl_get_peer_id ((b)->id))
DEFINE_TREE(user, struct tgl_user *,user_cmp,0)
static void notify_status (struct tgl_user *U, void *ex) {
struct tgl_state *TLS = ex;
if (TLS->callback.user_status_update) {
TLS->callback.user_status_update (TLS, U);
}
}
static void status_notify (struct tgl_state *TLS, void *arg) {
tree_act_ex_user (TLS->online_updates, notify_status, TLS);
tree_clear_user (TLS->online_updates);
TLS->online_updates = NULL;
TLS->timer_methods->free (TLS->online_updates_timer);
TLS->online_updates_timer = NULL;
}
The tree_act_ex_user function is not defined anywhere and IDE is navigating to second line i.e. DEFINE_TREE(user, struct tgl_user *,user_cmp,0). Please explain or point to a reference what construct is this?
what construct is this?
A macro expansion that defines a function. A reduced example:
#define DEFINE_TREE(NAME, some_arg, some_arg2, yet_another_arg) \
static void tree_act_ex_##NAME() { \
do_something(); \
}
DEFINE_TREE(some_string, arg1, arg2, arg3)
// expands to:
// static void tree_act_ex_some_string() { do_something(); }
int main() {
tree_act_ex_some_string();
}
I am looking for a fancy way to link function pointers and enums.
In my case I have a message queue that holds a event id and some data associated with the event.
some simple pseudo code:
event=(eid, data)
switch(eid) {
case eid1:
handler1(data);
break;
case edi2:
handler2(data);
break;
}
Now I like to do some optimization. If the event id has the value of the function called inside of the switch case statement I can save the switch case decode by preserving a nice readability of the code.
event=(eid, data)
eid(data)
Now if I am putting it into an example like:
static void abc(void * p) {
}
static void abc2(void * p) {
}
enum eventId {
eid1 = abc,
eid2 = abc2
} xyz;
My compiler tells:
error: enumerator value for 'eid1' is not an integer constant eid1 = abc
What is absolutely right.
Any ideas how to solve that problem?
Use an array of function pointers, and use the enum as the index.
typedef void (*handler_func)(void *);
handler_func event_handlers[] = { abc, abc2 };
enum eventId {
eid1 = 0,
eid2 = 1,
eid_max
}
if (eid < eid_max) event_handlers[eid](data);
enums cannot be linked with other data in C, but the preprocessor can generate code for you in the form of X-Macros.
#include <stdio.h>
typedef void (*handler_func)(void *);
static void handler1(void *const param) {
printf("Event 1: %p.\n", param);
}
static void handler2(void *const param) {
printf("Event 2: %p.\n", param);
}
#define EVENT(X) \
X(EID1, &handler1), \
X(EID2, &handler2)
#define PARAMA(A, B) A
#define PARAMB(A, B) B
#define STRINGISEA(A, B) #A
enum Event { EVENT(PARAMA) };
static const handler_func event_handlers[] = { EVENT(PARAMB) };
static const char *const event_strings[] = { EVENT(STRINGISEA) };
/* Everything will be the same size, pick one. */
static const size_t event_size = sizeof event_strings / sizeof *event_strings;
int main(void) {
size_t i;
void *const param = (void *)0x100;
for(i = 0; i < event_size; i++) {
printf("Calling %s.\n", event_strings[i]);
event_handlers[i](param);
}
return 0;
}
Gives,
Calling EID1.
Event 1: 0x100.
Calling EID2.
Event 2: 0x100.
The advantage of this implementation is it's a single source of truth; if one decided to add more events, they will only need to be added in one spot. The disadvantage is it's hard to read.
As an extension to the answer of #Barmar, you can use a technique called X macro, to keep corresponding (eid, handler) pairs in order. Note that you need only to change the definition of LIST_OF_EVENTS macro, adding or deleting pairs as needed.
void handler1(void*);
void handler2(void*);
void handler3(void*);
#define LIST_OF_EVENTS X(eid1, handler1), X(eid2, handler2), X(eid3, handler3)
#define X(id, x) id
enum evID { LIST_OF_EVENTS };
#undef X
#define X(x, handler) handler
void (*handlers[])(void*) = { LIST_OF_EVENTS };
#undef X
int get_event(void**);
void event_loop(void)
{
for (;;) {
void *data;
int eid = get_event(&data);
handlers[eid](data);
}
}
Macro defitions expand to
enum evID { eid1, eid2, eid3 };
void (*handlers[])(void*) = { handler1, handler2, handler3 };
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)
When using the tail queue implementation from sys/queue.h, why does the following code work:
item_t *item = mkitem(...);
TAILQ_INSERT_HEAD(&list, item, entry);
while the following, which should be equivalent, does not:
TAILQ_INSERT_HEAD(&list, mkitem(...), entry);
Minimal working example
#include <stdlib.h>
#include <stdio.h>
#include <sys/queue.h>
typedef struct item item_t;
typedef TAILQ_HEAD(list_head, item) list_head_t;
struct item {
int value;
TAILQ_ENTRY(item) entry;
};
static list_head_t items = TAILQ_HEAD_INITIALIZER(items);
static item_t* mkitem(int i) {
item_t *item = calloc(1, sizeof(item_t));
item->value = i;
return item;
}
static void print_tailq() {
item_t *it;
TAILQ_FOREACH(it, &items, entry) {
printf("%d,", it->value);
}
printf("\n");
}
int main() {
item_t *i1, *i2, *i3;
i1 = mkitem(1);
i2 = mkitem(2);
i3 = mkitem(3);
TAILQ_INSERT_HEAD(&items, i1, entry);
print_tailq();
TAILQ_INSERT_HEAD(&items, i2, entry);
print_tailq();
TAILQ_INSERT_TAIL(&items, i3, entry);
print_tailq();
/* However, this does not work: */
TAILQ_INSERT_HEAD(&items, mkitem(4), entry);
print_tailq();
TAILQ_INSERT_HEAD(&items, mkitem(5), entry);
print_tailq();
TAILQ_INSERT_TAIL(&items, mkitem(6), entry);
print_tailq();
return 0;
}
As expected, the first three invocations of print_tailq() print out, respectively:
1,
2,1,
2,1,3,
However, the last three invocations show that the list is truncated by TAILQ_INSERT_HEAD, and TAILQ_INSERT_TAIL is essentially a no-op.
4,
5,
5,
From here the implementation of TAILQ_INSERT_HEAD macro TAILQ_INSERT_HEAD(head, elm, field)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
It is macro which is being expanded - so it is basically replacing the elm with multiple calls to mkitem(). Passing directly the results of mkitem() invokes erroneous behavior in your code. Using mkitem directly overwrites the previous list (there is a memory leak) and the new list with single element is created - which is printed. You have to use a variable here like you did earlier - otherwise it won't work. Actually you thought that this is a function which it is not. (You will see that man page examples also reflect this idea of using a variable)
Say I have the following code:
struct test* t1;
t1 = get_t(1);
... where get_t is:
struct test* get_t(int);
How can I refactor the above code and put it in a function? Something like the following:
void r1(?* t, ?* (fn*)(int)) {
t = fn(1);
}
/* ... */
struct test* t1;
r1(t1, &get_t);
use void *param, a pointer to anything ... commonly used in glib as gpointer
I have two ideas:
[1] Pass void pointer to the variable/object, and type cast it in the function.
[2] Make a union of all datatypes along with an integer datatype which will identify which datatype variable in the union does hold the actual data. Pass this union as value or as void *
struct _unknown {
union {
int a;
float b;
char c;
double d;
} data;
int type;
} unknown;
.
.
.
if (unknown.type == FLOAT)
{
/* Process variable b */
}
else if (unknown.type == INT)
{
/* Process variable a */
}
.
.
.
Something like this.
You can hash define the FLOAT and INT and others as unique values.
Or simply
struct _unknown {
void *data;
int type;
} unknown;
.
.
.
if (unknown == FLOAT)
{
/* process (float *) data */
}
else if (unknown == INT)
{
/* process (int *) data */
}
else if (unknown == MY_DATA_TYPE)
{
/* process (my_data_type *) data */
/* where my_data_type could be a typedef, or struct */
}
If you have gcc, you can use this more typesafe version:
#define r1(varp,func) ({ \
typeof(**varp)* (*_func_)(int); \
typeof(**varp)* _varp_ = (varp); \
_func_ = (func); \
r1_((void**)(_varp_),(void*(*)(int))_func_); \
})
void r1_(void** varp,void*(*func)(int))
{
*varp = func(1);
}
Call as:
struct test* get_t(int);
struct test* t1;
r1(&t,get_t);
(You dont need to use & on functions, they decay to pointers automatically, like arrays). This checks that t is a pointer, and that get_t is a function returning that type of pointer. _varp_ is technically unneeded, but keeps the argument evaluation in the right order.
Edit:
If you don't have gcc, you can still do this, but you have to provide the type explicitly:
#define r1(T,varp,func) do { \
T*(*_func_)(int); \
T* _varp_ = (varp); \
_func_ = (func); \
r1_((void**)(_varp_),(void*(*)(int))_func_); \
} while(0)
void r1_(void** varp,void*(*func)(int))
{
*varp = func(1);
}
Call as:
struct test* get_t(int);
struct test* t1;
r1(struct test*,&t,get_t);
not quite as safe, and more redundant, but still fairly good.