Parameter of macro mixed with field of structure - c

So I have macro like this:
#define some_macro(param1) \
static some_struct_t struct = \
{ \
.param1 = param1 \
}
When I call this macro from main with direct value:
some_macro(50);
I got an error :
..\..\main.c(185): error: #29: expected an expression
I found 2 ways to solve it, first was to declare const value within main and pass to macro and second to change name of parameter not be the same as in macro.
So it works but I do not what caused error. Any ideas?

struct is a reserved word, you can not use it as a variable name
Change to something like:
#define some_macro(p1) \
static some_struct_t valid_var_name = \
{ \
.param1 = p1 \
}
If you want to use the same name of the member (param1) as the name of your macro parameter you need to stop the expansion (using ##) or you get .50 = 50
#define some_macro(param1) \
static some_struct_t varname = \
{ \
.param##1 = param1 \
}

There are a few issues with it.
some_struct_t struct is wrong. if some_struct_t is a typedef for a struct or a define for one, you need to do some_struct_t myStruct else struct some_struct_t myStruct
Another issue is, in the code your macro generates, you'll have something like the following (assuming the problem above is fixed):
struct some_struct_t myStruct = { .50 = 50 };
I believe you didn't intend to use 50 as an identifier :)
This may be more like what you want:
#define some_macro(key, value) \
struct some_struct_t myStruct = {\
.key = value\
}
Or if you already know which variable you want to set:
#define some_macro(value) \
struct some_struct_t myStruct = {\
.param1 = value\
}

Related

C MacroMagic - Struct Definition

Im looking for a solution for define a struct, where the user may enable/disable struct members as in the example (pseudo-code):
#define DEF_STRUCT_1(NAME,VAL1,VAL2) \
struct my_struct_t \
{ \
#if(NAME == TRUE) \
bool name; \
#endif \
#if(VAL1 == TRUE) \
bool val1; \
#endif \
#if(VAL2 == TRUE) \
bool val2; \
#endif \
} instance1
void main() {
DEF_STRUCT_1(TRUE,FALSE,TRUE);
instance1.name = true;
//instance1.val1 = false; // error, unavailable
instance1.val2 = false;
}
I'm not sure how useful this is, but the following should do what you ask:
#define CONDITIONAL_TRUE(code) code
#define CONDITIONAL_FALSE(code)
#define DEF_STRUCT_1(NAME,VAL1,VAL2) \
struct my_struct_t \
{ \
CONDITIONAL_##NAME(bool name;) \
CONDITIONAL_##VAL1(bool val1;) \
CONDITIONAL_##VAL2(bool val2;) \
} instance1
int main() {
DEF_STRUCT_1(TRUE,FALSE,TRUE);
instance1.name = true;
//instance1.val1 = false; // error, unavailable
instance1.val2 = false;
}
All the TRUE/FALSE parameters would have to be available at compile-time. And if you want more than one version of these parameters to be used in the same program, you should make the struct name a parameter as well.
Since you say that this is intended for a library, it isn't clear how you're planning for the library code to be able to access this struct, since it would need to know which members are available. This significantly reduces the usefulness of this method.
A more common method used by libraries is to have a config.h file, editable by the library user, with definitions such as #define USE_NAME_MEMBER 1. Then you can make a normal struct definition with #if directives:
//in mylibrary.h:
#include <mylibrary_config.h>
struct my_struct_t {
#if USE_NAME_MEMBER
bool name;
#endif
/...
};
Then you would also put #if directives around any library code that accesses the name member.
Given that the struct needs to be generated differently at compile-time, given some conditions, you will be facing the problem that all code using the struct will need to be modified accordingly. Compiler switches (#ifdef FOO .... #endif) tend to scale badly with increased complexity. If there is a large number of struct members, all the needed compiler switches will make a horrible, unmaintainable mess out of the program.
There is a well-known design pattern known as "X macros", that can be used to centralize maintenance in programs to one single place, as well as allowing compile-time iteration of all items involved. They make the code hard to read too, and therefore they are a bit of a last resort. But they are a bit of de facto standard and their ugliness doesn't scale with complexity, so they are preferred over some compiler switch madness. It goes like this:
#define INSTANCE_LIST \
/* name, type */ \
X(name, bool) \
X(val1, bool) \
X(val2, bool) \
typedef struct
{
#define X(name, type) type name;
INSTANCE_LIST
#undef X
} instance_t;
This code gets pre-processed into:
typedef struct
{
bool name;
bool val1;
bool val2;
} instance_t;
The only part that needs to be maintained is the "INSTANCE_LIST". By commenting out a line in the list, that struct member will go away. This means that all code using the struct has to be using the same list accordingly. For example, lets add code to the same example, that lists the init values of each member and then sets them:
#include <stdbool.h>
#include <stdio.h>
#define INSTANCE_LIST \
/* name, type, init */ \
X(name, bool, true) \
X(val1, bool, false) \
X(val2, bool, false) \
typedef struct
{
#define X(name, type, init) type name;
INSTANCE_LIST
#undef X
} instance_t;
int main (void)
{
instance_t inst;
#define X(name, type, init) inst.name = init;
INSTANCE_LIST
#undef X
printf("%d ", inst.name);
printf("%d ", inst.val1);
printf("%d ", inst.val2);
}
Very flexible and maintainable - you can easily add more struct members without changing any other macro than the list. But as mentioned, the down-side is that the code looks quite cryptic, especially to those who aren't used to this design pattern.

Write vargarg C preprocessor macro which calls some other macro with each of its arguments and more

I need to have meta-information about structures in my code. So, I've code some combination of C structures (to store meta information) and C preprocessor macros to initialize these structures without much of boilerplate code. Now it looks like this (really, I'm storing a lot more information about fields, but this code is enough for my question):
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
struct meta_field {
const char *name;
size_t offset;
};
struct meta_struct {
const char *name;
size_t size;
struct meta_field fields[];
};
#define META_STRUCT_BEGIN(NAME) \
static struct meta_struct s_meta_##NAME = { \
.name = "" #NAME, \
.size = sizeof(struct NAME), \
.fields = {
#define META_STRUCT_END() ,{NULL, 0}}}
#define META_FIELD(NAME) { .name = "" #NAME, .offset = offsetof(struct CURRENT_META_STRUCT, NAME) }
struct example {
int i;
double d;
};
#define CURRENT_META_STRUCT example
META_STRUCT_BEGIN(CURRENT_META_STRUCT)
META_FIELD(i),
META_FIELD(d)
META_STRUCT_END();
#undef CURRENT_META_STRUCT
It works. But it has a lot of boilerplate still: #define CURRENT_META_STRUCT, usage of CURRENT_META_STRUCT as argument to META_STRUCT_BEGIN(), #undef for CURRENT_META_STRUCT — all of this looks ugly, IMHO.
I know, that it is impossible to define macro by macro (so, META_STRUCT_BEGIN() can not define CURRENT_META_STRUCT). But looking at Branf*ck implementation in C Preprocessor and Boost-PP, I think that it is posisble to implement something which will look like this:
META_STRUCT(example,
META_FIELD(i),
META_FIELD(d)
)
But I can not wrap my head around this preprocessor magic.
Could somebody helps me?
I've read https://github.com/orangeduck/CPP_COMPLETE already, but it didn't help.
Also, it was marked as duplicate of this, but problem is I need to add "default" argument to all generated macro "calls".
Here are some sketch, what I want to achieve:
#define META_FIELD_IMPL(STRUCT, NAME) { .name = "" #NAME, .offset = offsetof(struct STRUCT, NAME) }
#define META_FIELD(NAME) NAME
#define META_STRUCT(NAME, ... ) \
static struct meta_struct s_meta_##NAME = { \
.name = "" #NAME, \
.size = sizeof(struct NAME), \
.fields = { \
/* Each ARG from __VA_ARGS__ is META_FIELD(x) and \
* I need to call META_FIELD_IMPL(NAME, <Expansion of META_FIELD>) \
* for each ARG from _VA_ARGS_ here */ \
{NULL, 0} \
}}
Now in this example there is only one argument for META_FIELD(): NAME, but in real system there are 6 arguments for META_FIELD() and some helper macro which provide "default" values for common cases, so META_FIELD() is necessary and could not be replaced by NAME itself.
And one last complication: such META_STRUCT() could be called as argument to META_FIELD(), because some fields contains pointers to nested meta-structs! Now it is done by declaring named objects for all nested sub-structures, but I want to avoid it too! I understand, that depth of nesting could be limited by some arbitrary constant, it is Ok.
Update: I added this example of what I want to type and what I want to get after preprocessor. I can not figure out how to implement all these macros (marked with /* ??? */). And, yes, I've checked, manually-coded "end result" compiles fine.
enum meta_type { mt_end, mt_int, mt_string, mt_struct };
struct meta_struct;
struct meta_field {
const char *name;
enum meta_type type;
size_t offset;
struct meta_struct *child;
};
struct meta_struct {
const char *name;
size_t size;
struct meta_field *fields;
};
#define META_STRUCT(NAME, ...) static struct meta_struct s_meta_##name = { .name = #NAME, .size = sizeof(struct NAME), .fileds = (struct meta_field[]){ /* ??? */, {NULL, mt_end, 0, NULL}}}
#define META_FIELD_IMPL0(STRUCT, NAME, TYPE, CHILD) { .name = #NAME, .type = TYPE, .offset = offsetof(STRUCT, NAME), .child = CHILD }
#define META_FIELD_IMPL1(NAME, TYPE, CHILD) /* ??? */
#define META_FIELD(NAME, TYPE) META_FIELD_IMPL1(NAME, TYPE, NULL)
#define META_FIELD_SUB(NAME, CHILD) META_FIELD_IMPL1(NAME, mt_struct, CHILD)
#define META_SUBSTRUCT(NAME, ...) (struct meta_struct){ .name = #NAME, .size = sizeof(struct NAME), .fileds = (struct meta_field[]){ /* ??? */, {NULL, mt_end, 0, NULL}}}
/* Example of "input": */
struct child {
int i;
};
struct parent {
int i;
struct child c;
const char *s;
};
META_STRUCT(parent,
META_FIELD(i, mt_int),
META_FIELD_SUB(c,
META_SUBSTRUCT(child,
META_FIELD(i, mt_int)
)
),
META_FIELD(s, mt_string)
);
/* This should give this */
static struct meta_struct s_meta_parent = {
.name = "parent",
.size = sizeof(struct parent),
.fields = (struct meta_field[]) {
{ .name = "i", .type = mt_int, .offset = offsetof(struct parent, i), .child = NULL },
{ .name = "c", .type = mt_struct, .offset = offsetof(struct parent, c), .child = &(struct meta_struct){
.name = "child",
.size = sizeof(struct child),
.fields = (struct meta_field[]) {
{ .name = "i", .type = mt_int, .offset = offsetof(struct child, i), .child = NULL },
{NULL, mt_end, 0, NULL}
}
}
},
{ .name = "s", .type = mt_string, .offset = offsetof(struct parent, s), .child = NULL },
{NULL, mt_end, 0, NULL}
}
};
Here's an approach.
Basic utilities
#define GLUE(A,B) GLUE_I(A,B)
#define GLUE_I(A,B) A##B
#define COUNT(...) COUNT_I(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1,)
#define COUNT_I(V,_9,_8,_7,_6,_5,_4,_3,_2,X,...) X
This is an indirect glue macro (allowing arguments to expand) and a count macro. The count macro here supports only 9 arguments, but it's easy to expand the pattern. This just expands to the number of arguments passed. I'm assuming you've seen this before, but just in case you haven't, this just works by argument shifting; it indirectly expands the arguments, and each extra argument shift above 1 displaces the number list until something is "above" X, which it expands to.
#define FIRST(...) FIRST_I(__VA_ARGS__,)
#define FIRST_I(X,...) X
#define REST(X,...) __VA_ARGS__
#define EXPAND(...) __VA_ARGS__
...these are operations on tuples. For the purposes of this answer, a tuple is a set of tokens in parentheses. FIRST and REST use tuples as data types (should be obvious; FIRST indirectly grabs the first element, REST expands to everything but that). EXPAND unwraps a tuple.
And the next utility macro:
#define FOREACH(MACRO_,DATA_,TUPLE_) GLUE(FOREACH_I_,COUNT TUPLE_)(MACRO_,DATA_,TUPLE_)
#define FOREACH_I_1(MACRO_,DATA_,TUPLE_) MACRO_(DATA_,FIRST TUPLE_)
#define FOREACH_I_2(MACRO_,DATA_,TUPLE_) MACRO_(DATA_,FIRST TUPLE_) FOREACH_I_1(MACRO_,DATA_,(REST TUPLE_))
#define FOREACH_I_3(MACRO_,DATA_,TUPLE_) MACRO_(DATA_,FIRST TUPLE_) FOREACH_I_2(MACRO_,DATA_,(REST TUPLE_))
#define FOREACH_I_4(MACRO_,DATA_,TUPLE_) MACRO_(DATA_,FIRST TUPLE_) FOREACH_I_3(MACRO_,DATA_,(REST TUPLE_))
#define FOREACH_I_5(MACRO_,DATA_,TUPLE_) MACRO_(DATA_,FIRST TUPLE_) FOREACH_I_4(MACRO_,DATA_,(REST TUPLE_))
#define FOREACH_I_6(MACRO_,DATA_,TUPLE_) MACRO_(DATA_,FIRST TUPLE_) FOREACH_I_5(MACRO_,DATA_,(REST TUPLE_))
#define FOREACH_I_7(MACRO_,DATA_,TUPLE_) MACRO_(DATA_,FIRST TUPLE_) FOREACH_I_6(MACRO_,DATA_,(REST TUPLE_))
#define FOREACH_I_8(MACRO_,DATA_,TUPLE_) MACRO_(DATA_,FIRST TUPLE_) FOREACH_I_7(MACRO_,DATA_,(REST TUPLE_))
#define FOREACH_I_9(MACRO_,DATA_,TUPLE_) MACRO_(DATA_,FIRST TUPLE_) FOREACH_I_8(MACRO_,DATA_,(REST TUPLE_))
This is the key macro; it is in practice used to apply your structure's type into the lower level macros for each field. Again, this particular code only works with 9 fields per level, but it should be obvious how to extend this (you probably want to support as many levels as your COUNT macro can count to).
The third argument of FOREACH should be a tuple; FOREACH's job is to call your macro on DATA_ and each element of TUPLE_. For example, FOREACH(FIELD,parent,(i,j,k)) expands to FIELD(parent,i) FIELD(parent,j) FIELD(parent,k).
Concept for specific utilities
The core calling structure for the specific utilities uses tuple data types; when used with the FOREACH macro, underlying calls will curry the outer structure type into each call appropriately. The calling structure looks like this:
META_STRUCT(type , FIELD[ , FIELD[ ... ] ] )
...where each FIELD is a 3-tuple:
(name , type , CHILD )
...and each CHILD is a tuple, which is expanded into a .child assignment. META_SUBSTRUCT works similarly. So according to this call structure, your example will actually wind up being called like this:
META_STRUCT(parent, (i, mt_int, (NULL)), (c, mt_struct, META_SUBSTRUCT(child,(i,mt_int,(NULL)))),(s, mt_string, (NULL)));
In practice, META_SUBSTRUCT will actually fully expand. Its expansion will be a "tuple of tokens" that acts as the child assignment; that is, META_SUBSTRUCT will expand to the actual assignments in the substruct surrounded by parentheses. The FOREACH macro is applied to this construct, currying the outer structure and the three arguments of the above 3-tuple into the 4-argument macro APPLY_UTILI_FIELD.
The usage mirrors your usage and adopts to this call structure. For example, META_FIELD(i, mt_int) is just a macro that expands to (i, mt_int, (NULL)).
Specific utilities
#define META_STRUCT_BEGIN(NAME_) \
static struct meta_struct s_meta_##NAME_ = { \
.name = #NAME_, \
.size = sizeof(struct NAME_), \
.fields = (struct meta_field[]) {
#define META_STRUCT(NAME_,...) \
META_STRUCT_BEGIN(NAME_) \
FOREACH(APPLY_META_STRUCT_MACRO,NAME_,(__VA_ARGS__)) \
META_STRUCT_END()
#define META_STRUCT_END() \
{NULL, mt_end, 0, NULL}}}
#define META_SUBSTRUCT(NAME_,...) \
( META_SUBSTRUCT_BEGIN(NAME_) \
FOREACH(APPLY_META_STRUCT_MACRO,NAME_,(__VA_ARGS__)) \
META_SUBSTRUCT_END() )
#define META_SUBSTRUCT_BEGIN(NAME_) \
&(struct meta_struct) { \
.name = #NAME_, \
.size = sizeof(struct NAME_), \
.fields = (struct meta_field[]) {
#define META_SUBSTRUCT_END() \
{NULL, mt_end, 0, NULL}}}
#define APPLY_META_STRUCT_MACRO(DATA_, ARG_) APPLY_UTIL_FIELD(DATA_, EXPAND ARG_)
#define APPLY_UTIL_FIELD(...) APPLY_UTILI_FIELD(__VA_ARGS__)
#define APPLY_UTILI_FIELD( STRUCT_, FIELD_, TYPE_, CHILD_) \
{ .name = #FIELD_, .type = TYPE_, .offset = offsetof(struct STRUCT_, FIELD_), .child = EXPAND CHILD_ },
#define META_FIELD(NAME_, TYPE_) (NAME_, TYPE_, (NULL))
#define META_FIELD_SUB(NAME_, SUB_) (NAME_, mt_struct, SUB_)
Demo
Showing your example
Notes
Nesting
These macros allow nesting indefinitely of META_SUBSTRUCT calls without running into blue paint, since all such macros wind up being evaluated in the argument substitution phase (... argument mentioning __VA_ARGS__ causes all arguments to expand; each level of META_SUBSTRUCT is a top level expansion in this scenario; this condition recurses).
Your six fields
Given you're showing an example with less fields than you're using, you need specifically to tweak your user defined META_FIELD, META_FIELD_SUB, etc macros to produce k-tuples instead of 3-tuples (where k is what you need). Then, just adjust APPLY_UTILI_FIELD's arguments and expansion to match.
Microsoft Compatibility
This code assumes a standard C preprocessor. If you're working on MSVC specifically (which doesn't have one), it won't work. Specifically, MSVC fails to expand __VA_ARGS__ when it's supposed to; if you care to work on MSVC, change the corresponding macros for these three to:
#define COUNT(...) EXPAND(COUNT_I(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1,))
#define FIRST(...) EXPAND(FIRST_I(__VA_ARGS__,))
#define APPLY_UTIL_FIELD(...) EXPAND(APPLY_UTILI_FIELD(__VA_ARGS__))
The result should also work on standard compliant CPP's.
How about using __VA_ARGS__? Codesnip below accepts maximize 4 fields but you can expands to 5, 6 or more by copy and paste some line of codes (refer here for more detail).
Header file:
#define META_FIELD1(st,x1) { .name = #x1, .offset = offsetof(struct st, x1) }
#define META_FIELD2(st,x1,x2) META_FIELD1(st,x1), META_FIELD1(st, x2)
#define META_FIELD3(st,x1,x2,x3) META_FIELD1(st,x1), META_FIELD2(st,x2,x3)
#define META_FIELD4(st,x1,x2,x3,x4) META_FIELD1(st,x1), META_FIELD3(st,x2,x3,x4)
#define META_FIELD(st, ...) META_FIELD4(st, ##__VA_ARGS__) // limit to 4
#define META_STRUCT(st, ...) \
static struct meta_struct meta_struct_##st = { \
.name = #st, \
.size = sizeof(struct st), \
.fields = { \
META_FIELD(st, ##__VA_ARGS__) \
} \
} \
C file:
struct sample {
int i;
double d;
const char *test;
float t;
};
META_STRUCT(sample, i, d, test, t);
/*
*
*/
int main(int argc, char** argv) {
printf("struct %s { %s, %s, %s, %s } \n",
meta_struct_sample.name,
meta_struct_sample.fields[0].name,
meta_struct_sample.fields[1].name,
meta_struct_sample.fields[2].name,
meta_struct_sample.fields[3].name);
return (EXIT_SUCCESS);
}
Output should be: struct sample { i, i, test, t }

How write macro to avoid redefine?

I have the follow macro:
#define my_add_property(ret, name, value) \
object tmp; \
tmp = *value; \
add_property(ret, name, &tmp);
Now I use the macro in the follow function:
void func() {
object *ret;
my_add_property(ret, "key", my_func1());
my_add_property(ret, "value", my_func2());
}
It will have make error: tmp is redefined.
So I want to use object tmp##name, but if name is "key", tmp##name will be tmp"key". I should do how write the macro that make tmp##name to tmpkey not tmp"key"? thanks!
You can create a new scope inside your macro, such that tmp is only live for a short amount of time by wrapping the implementation in a do {} while(0), for example:
#define my_add_property(return, name, value) do { \
object tmp; \
tmp = *value; \
add_property(return, name, &tmp); } while(0)

Creating generics with typedef in C

I'm doing my hw in C right now and we were given the code below in lecture to create generic types. In C++, I know you can achieve this by just using templates. Our instructor wants us to use these (so no void* for now I don't think).
However, I'm confused as to how I can declare this.
typedef struct Cell(x) *List(x);
struct Cell(x) {
x* data;
List(x) next;
};
So, I know whenever the compiler sees
List(x),
it will substitute in struct Cell(x), so I tried doing List(int) a; in main(), but that doesn't work
New versions of C added "type-generic expressions", allowing for example the abs function to do different things with different argument types.
But as far as I know, there are still no generic types. Your choices for implementing collection types:
Give up type-safety, using void*
Type out the collection / container code for each element type.
Use macros to generate the same code as #2.
I suspect you're intended to do #3. Something along the lines of:
#define Cell(x) specialized_##x##_Cell
#define List(x) specialized_##x##_List
#define SINGLY_LINKED_LIST(x) \\
typedef struct Cell(x) *List(x); \\
struct Cell(x) \\
{ \\
x* data; \\
List(x) next; \\
};
and then you can use it like
SINGLY_LINKED_LIST(int)
int main(void)
{
List(int) a;
}
There is a way you can fake templates for generics like containers in C with macros. You must write two macros that generate declarations and the definition of a new struct type and the functions acting on this type.
For example for an (incomplete) list type:
#define DECLARE_LIST(T_Name, T_Tag, T_Type) \
\
typedef struct T_Name##Node T_Name##Node; \
typedef struct T_Name T_Name; \
\
struct T_Name { \
T_Name##Node *head; \
T_Name##Node *tail; \
int count; \
}; \
\
struct T_Name##Node { \
T_Type value; \
T_Name##Node *next; \
}; \
\
int T_Tag##_init(T_Name *ll); \
int T_Tag##_free(T_Name *ll); \
int T_Tag##_add(T_Name *ll, T_Type x);
#define DEFINE_LIST(T_Name, T_Tag, T_Type) \
\
int T_Tag##_init(T_Name *ll) \
{ \
ll->head = ll->tail = NULL; \
ll->count = 0; \
return 0; \
} \
\
int T_Tag##_free(T_Name *ll) \
{ \
while (ll->head) { \
T_Name##Node *next = ll->head->next; \
free(ll->head); \
ll->head = next; \
} \
return 0; \
} \
\
int T_Tag##_add(T_Name *ll, T_Type x) \
{ \
T_Name##Node *nd = malloc(sizeof(*nd)); \
\
if (nd == NULL) return -1; \
nd->next = NULL; \
nd->value = x; \
\
if (ll->head == NULL) { \
ll->head = ll->tail = nd; \
} else { \
ll->tail->next = nd; \
ll->tail = nd; \
} \
ll->count++; \
\
return 0; \
}
#define IMPLEMENT_LIST(T_Name, T_Tag, T_Type) \
DECLARE_LIST(T_Name, T_Tag, T_Type) \
DEFINE_LIST(T_Name, T_Tag, T_Type) \
If you want to declare a new List type, you should DECLARE_LIST in a header and DEFINE_LIST in the C source. If the type is private to the compilation module, you can just place IMPLEMENT_LIST in the C source.
(The macro is incomplete, because it implements only three functions for the type, which are useless on their own. This is just to show the basic workings. You will usually end up with two huge macros.)
You can use the macro like this:
IMPLEMENT_LIST(Intlist, il, int)
IMPLEMENT_LIST(Stringlist, sl, char *)
This creates two new list types, Intlist and Stringlist, together with the according functions, prefixed il_ and sl_, which you can use like other functions:
int main()
{
Intlist il;
Stringlist sl;
il_init(&il);
sl_init(&sl);
il_add(&il, 1);
il_add(&il, 2);
il_add(&il, 5);
sl_add(&sl, "Hello");
sl_add(&sl, "World");
// ... more stuff ...
il_free(&il);
sl_free(&sl);
return 0;
}
This method is type safe: You can't pass a Stringlist to an il function, for example. Because the code consists only of macros, you can implement it in a header file.
There are restrictions, though:
Assignment is via =. That means that the string list for example can't keep a copy in a char array. If the client code copies data, the clean-up code doesn't know about it. You can cater for such cases by specifying copy, comparison, constructor and destructor functions (which can also be macros) as macro arguments, but this will quickly become complicated.
There are "secret" type names involves like the node type in the example above. They must be valid identifiers (as opposed to C++, where the compiler creates mangles names), which might lead to surprising name clashes.
When you use a private implementation, the functions aren't static as they ought to be.
It has the advantage, that Stringlist is a nicer name than std::list<std::string>, though.

Pass anonymous struct as parameter in C

I have the following line of c (carriage returns added for readability - they aren't in the code):
#define i2c_write(slave_addr, reg_addr, len, *data_ptr)
twi_master_write(MPU_TWI, {
.addr = reg_addr,
.addr_length = 1,
.buffer = *data_ptr,
.length = len,
.chip = slave_addr
})
Where twi_master_write() is declared as:
uint32_t twi_master_write(Twi *p_twi, twi_packet_t *p_packet);
and twi_packet_t is declared as:
typedef struct twi_packet {
uint8_t addr[3];
uint32_t addr_length;
void *buffer;
uint32_t length;
uint8_t chip;
} twi_packet_t;
The parameters of twi_write() are all required to be of type unsigned char.
When compiling, I receive the following error:
expected expression before '{' token
Is there a correct way to do what I'm trying to do here, or is it just not possible?
My take on it, in a compilable sample. This is a compilation stub and will not run correctly, so don't try to run it as-is !
//
// Cobbling up a compilation stub
//
#include <stdint.h>
struct Twi;
typedef struct Twi Twi;
#define MPU_TWI (Twi*)0
typedef struct twi_packet {
uint8_t addr[3];
uint32_t addr_length;
void *buffer;
uint32_t length;
uint8_t chip;
} twi_packet_t;
uint32_t twi_master_write(Twi *p_twi, twi_packet_t *p_packet);
//
// Now for my answer :
//
#define i2c_write(slave_addr, reg_addr, len, data_ptr) \
twi_master_write(MPU_TWI, &(twi_packet_t){ \
.addr = reg_addr, \
.addr_length = 1, \
.buffer = *data_ptr, \
.length = len, \
.chip = slave_addr \
})
main()
{
// Trigger that macro !
i2c_write(0, 0, 0, (void**)0);
}
This instanciates a compound literal and passes its address to the function. The literal's lifetime does not exceed that of the full call expression.
Here's a more readable and correct way to write the macro.
It will work in all cases of if/else clauses and the struct is defined within a scope so it's name is local and doesn't pollute your name space.
#define i2c_write(_slave_addr, _reg_addr, _len, _data_ptr) \
do { \
twi_packet_t temp = { \
.addr = _reg_addr, \
.addr_length = 1, \
.buffer = _data_ptr, \
.length = _len, \
.chip = _slave_addr }; \
\
twi_master_write(MPU_TWI, &temp); \
} while (0)
It would be better if you provide a simple complete set of a code, so that we can execute here and help you. Meanwhile, i dont think you can use the '*' in the macro, since, macro patameters are not typed. What macro does is just a substitution of a symbol.

Resources