Defining a struct along with a str dictionary using a macro - c

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.

Related

how to define a c macro that returns a function name according to the argument?

What I currently have
#define _CMPLT8 _mm_cmplt_epi8 // int8_t
#define _CMPLT32 _mm_cmplt_epi32 // int32_t
What I want (something similar to the following code)
#define _CMPLT(T) ( \
if(sizeof(T)==1) return _mm_cmplt_epi8 \
else if(sizeof(T)==4) return _mm_cmplt_epi32 \
else #error \
)
How could I this code?
If you want to return a string based on a type I'd go for generics:
#define _CMPLT(T) \
_Generic( (T), \
char: "1", \
int: "4", \
default: "0")
int main(void) {
char a;
int b;
printf("%s%s\n", _CMPLT(a), _CMPLT(b));
}
But I feel you want to call functions depending on arg type, so in that case:
#define _CMPLT(X, Y) _Generic((X), \
int8_t: _mm_cmplt_epi8(X, Y), \
int32_t: _mm_cmplt_epi32(X, Y) \
)
int main(void) {
int8_t a = 0, b = 1;
int32_t c = 2, d = 3;
printf("%d%d\n", _CMPLT(a, b), _CMPLT(c, d));
}
If you really need to use strings and sizeof, and can use compound statements, would this work for you?
#include <stdio.h>
#define _CMPLT(T) ({ \
switch(sizeof(T)) { \
case 1: "1"; \
case 4: "4"; \
}; \
"0"; \
})
int main(void) {
printf("%s%s\n",
_CMPLT(char), _CMPLT(int));
}

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)

Preproccesor macro to

Im trying to create a preprocessor macro to allocate and free memory for matrix/vector of any data type. Here is what I have so far:
#ifndef H_ARRAY_H
#define H_ARRAY_H
#include "xmalloc.h"
#define make_vector(v,n) (v = xmalloc( (n) * sizeof *(v))
#define free_vector(v) do { free(v) ; v = NULL; } while(0)
#define make_matrx(a , m , n) do { \
size_t make_matrix_loop_counter; \
make_vector(a, (m) + 1); \
for ( make_matrix_loop_counter = 0; make_matrix_loop_counter < (m) ; make_matrix_loop_counter++) \
make_vector((a)[make_matrix_loop_counter], (n)); \
(a)[m] = NULL; \
} while (0)
#define free_matrix(a) do { \
if (a != NULL){ \
size_t make_matrix_loop_counter; \
for (make_matrix_loop_counter = 0 ; (a) [make_matrix_loop_counter] != NULL; make_matrix_loop_counter++) \
free_vector((a)[make_matrix_loop_counter]); \
free_vector(a); \
a != NULL; \
} \
} while (0)
But when I try to construct a matrix it spits out an error "implicit declaration of function ‘make_matrix’".
Any suggestions.
PS: xmalloc.h allocate space
Are you sure your MACRO name should read make_matrx instead of make_matrix?
You need to correct the macro name spelling. Otherwise, when you use make_matrix() in your code, it does not find a corresponding function.

Autogenerating a function wrapper in C

I want to create a function wrapper, with a defined body, that calls the wrapped function.
How can I get from this:
int foo (int arg)
{
do_something(arg);
}
To something equivalent to this:
int foo (int arg)
{
always_do_this();
real_foo(arg);
}
int real_foo (int arg)
{
do_something(arg);
}
I must do the transformation automatically and it has to be signature independent and in compile time.
How can I do it?
You can do this with macros, here's a quick example:
#define CREATE_FUNC_WRAPPER(NAME, ARG) \
int NAME(ARG arg) { \
real_##NAME(arg); \
}
int real_foo(int a) {
printf("real_foo speaking: %d\n", a);
}
CREATE_FUNC_WRAPPER(foo, int)
int main() {
foo(1);
}
You need to modify it to fit your needs, your question is unclear.
I had to give up from installing wrapper on function declaration, the solution was to install the wrappers on function call using compound statements. Bellow the two macros I created to do that, one deals with calls returning void, other with any call that returns a value:
#define PROFILE_VOID(call) \
({ \
hal_time_t stop, start; \
hal_getTime(&start); \
call; \
hal_getTime(&stop); \
__PROFILE_PRINT(call, hal_secondsElapsed_d(&stop, &start)); \
})
#define PROFILE(call) \
({ \
typeof(call) __ret; \
hal_time_t stop, start; \
__profile_nested_cnt++; \
hal_getTime(&start); \
__ret = call; \
hal_getTime(&stop); \
__profile_nested_cnt--; \
__PROFILE_PRINT(call, hal_secondsElapsed_d(&stop, &start)); \
__ret; \
})
Example of use:
PROFILE_VOID(func_returning_void(arg, arg2)); //Void func
PROFILE(other_funcs()); // Any non void func
PROFILE(x = func(x, y, z)); //Any statement
x = PROFILE(func(x, y, z)); //Same as previous
if (PROFILE(func()) == 0) { } //Inside conditionals
if (PROFILE(func() == 0)) { } //Same as previous

Boost Preprocessor Recursion

I'm trying to create a 'C' macro (not C++) that will define and initialize static data.
For example:
STATIC_CONST_STRUCT
(
A, a,
MEMBER_DATA(CONST_STR, a, "Hello, a")
MEMBER_DATA(CONST_STR, b, "Hello, b")
MEMBER_STRUCT
(
C, c,
MEMBER_DATA(CONST_STR, d, "Hello, d")
MEMBER_DATA(CONST_INT, e, 1)
)
);
Would cause the 'C' preprocessor to create:
static const struct A
{
CONST_STR a;
CONST_STR b;
struct C
{
CONST_STR d;
CONST_INT e;
} c;
} =
{"Hello, a", "Hello, b", {"Hello, d", 1}};
I've tried to use the Boost Preprocessor
http://www.boost.org/doc/libs/1_54_0/libs/preprocessor/doc/
but I can't quite figure out how to make this work. My macros stop expanding. I suspect the recursive nature of the problem having an arbitrarily deep nesting is why.
The solutions I read regarding getting the preprocessor to recurse either don't work, or the description of how to get recursion to work isn't clear enough to implement a working solution.
Here's what I have so far:
#define MEMBER_DATA_TAG 0
#define MEMBER_STRUCT_TAG 1
#define MEMBER_TAG(MEMBER) BOOST_PP_SEQ_ELEM(0, MEMBER)
#define MEMBER_DATA_TYPE(MEMBER_DATA) BOOST_PP_SEQ_ELEM(1, MEMBER_DATA)
#define MEMBER_DATA_NAME(MEMBER_DATA) BOOST_PP_SEQ_ELEM(2, MEMBER_DATA)
#define MEMBER_DATA_VALUE(MEMBER_DATA) BOOST_PP_SEQ_ELEM(3, MEMBER_DATA)
#define MEMBER_STRUCT_TYPE(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(1, MEMBER_STRUCT)
#define MEMBER_STRUCT_NAME(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(2, MEMBER_STRUCT)
#define MEMBER_STRUCT_MEMBER_SEQ(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(3, MEMBER_STRUCT)
#define MEMBER_DATA(TYPE, NAME, VALUE) ((MEMBER_DATA_TAG)(TYPE)(NAME)(VALUE))
#define MEMBER_STRUCT(TYPE, NAME, MEMBER_SEQ) ((MEMBER_STRUCT_TAG)(TYPE)(NAME)(MEMBER_SEQ))
#define IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM) BOOST_PP_EQUAL(MEMBER_TAG(MEMBER_SEQ_ELEM), MEMBER_STRUCT_TAG)
#define MEMBER_STRUCT_DECLARE(TYPE, NAME, MEMBER_SEQ) \
struct TYPE \
{ \
BOOST_PP_SEQ_FOR_EACH(MEMBER_ELEM_DECLARE, BOOST_PP_EMPTY(), MEMBER_SEQ) \
} NAME
#define MEMBER_ELEM_DECLARE(_r, _data, MEMBER_SEQ_ELEM) \
BOOST_PP_IIF \
( \
IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM), \
MEMBER_STRUCT_DECLARE \
( \
MEMBER_STRUCT_TYPE(MEMBER_SEQ_ELEM), \
MEMBER_STRUCT_NAME(MEMBER_SEQ_ELEM), \
MEMBER_STRUCT_MEMBER_SEQ(MEMBER_SEQ_ELEM) \
), \
MEMBER_DATA_DECLARE \
( \
MEMBER_DATA_TYPE(MEMBER_SEQ_ELEM), \
MEMBER_DATA_NAME(MEMBER_SEQ_ELEM), \
MEMBER_DATA_VALUE(MEMBER_SEQ_ELEM) \
) \
);
#define MEMBER_DATA_DECLARE(TYPE, NAME, VALUE) TYPE NAME
#define MEMBER_VALUE_INIT(MEMBER_SEQ) \
BOOST_PP_SEQ_FOR_EACH_I(MEMBER_VALUE_INIT_DECLARE, BOOST_PP_EMPTY(), MEMBER_SEQ);
#define MEMBER_VALUE_INIT_DECLARE(_r, _data, i, MEMBER_SEQ_ELEM) \
BOOST_PP_COMMA_IF(i) \
BOOST_PP_IIF \
( \
IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM), \
{MEMBER_VALUE_INIT(MEMBER_SEQ_ELEM)}, \
MEMBER_DATA_VALUE(MEMBER_SEQ_ELEM) \
)
#define STATIC_CONST_STRUCT(TYPE, NAME, MEMBER_SEQ) \
static const MEMBER_STRUCT_DECLARE(TYPE, NAME, MEMBER_SEQ) = \
{ \
MEMBER_VALUE_INIT(MEMBER_SEQ) \
}
Thanks.
It can be done without boost-preprocessor.
You don't actually need recursion. Just a loop to iterate over the macro arguments twice.
I took liberty of modifying the syntax a bit, to allow for commas in types and initializers, in case someone decides to use it with C++.
STATIC_CONST_STRUCT
(
A, a,
MEMBER_DATA(a, const char *) "Hello, a"
MEMBER_DATA(b, const char *) "Hello, b"
MEMBER_STRUCT
(
C, c,
MEMBER_DATA(d, const char *) "Hello, d"
MEMBER_DATA(e, int) 42
)
)
This expands to:
static const struct A
{
const char *a;
const char *b;
struct C
{
const char *d;
int e;
} c;
} a =
{
"Hello, a",
"Hello, b",
{
"Hello, d",
42,
},
};
Implementation:
#define STATIC_CONST_STRUCT(type_, name_, ...) \
static const struct type_ { \
END( LOOP_DECL_0 (__VA_ARGS__) ) \
} name_ = { \
END( LOOP_INIT_0 (__VA_ARGS__) ) \
};
#define MEMBER_DATA(name_, ...) )(var,name_,(__VA_ARGS__),
#define MEMBER_STRUCT(type_, name_, ...) )(open,type_ __VA_ARGS__ )(close,name_
#define IDENTITY(...) __VA_ARGS__
#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x##y
#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_END
#define LOOP_DECL_0() LOOP_DECL_A
#define LOOP_DECL_A(...) LOOP_DECL_BODY(__VA_ARGS__) LOOP_DECL_B
#define LOOP_DECL_B(...) LOOP_DECL_BODY(__VA_ARGS__) LOOP_DECL_A
#define LOOP_DECL_0_END
#define LOOP_DECL_A_END
#define LOOP_DECL_B_END
#define LOOP_DECL_BODY(action_, ...) CAT(LOOP_DECL_BODY_, action_)(__VA_ARGS__)
#define LOOP_DECL_BODY_var(name_, type_, ...) IDENTITY type_ name_;
#define LOOP_DECL_BODY_open(type_) struct type_ {
#define LOOP_DECL_BODY_close(name_) } name_;
#define LOOP_INIT_0() LOOP_INIT_A
#define LOOP_INIT_A(...) LOOP_INIT_BODY(__VA_ARGS__) LOOP_INIT_B
#define LOOP_INIT_B(...) LOOP_INIT_BODY(__VA_ARGS__) LOOP_INIT_A
#define LOOP_INIT_0_END
#define LOOP_INIT_A_END
#define LOOP_INIT_B_END
#define LOOP_INIT_BODY(action_, ...) CAT(LOOP_INIT_BODY_, action_)(__VA_ARGS__)
#define LOOP_INIT_BODY_var(name_, type_, ...) __VA_ARGS__,
#define LOOP_INIT_BODY_open(type_) {
#define LOOP_INIT_BODY_close(name_) },
If used with C++, IDENTITY type_ should be wrapped in std::type_identity_t<...> to allow using types such as function pointers without typedefing them. void (*)() foo; is illegal, while std::type_identity_t<void (*)()> foo; is ok.

Resources