Generic multiline macro with parameters - c

I'm trying to implement a generic stack in C, with the help of a big macro (not the best way, but that's not the point here).
This macro contains functions declarations, structures and functions calls, with a TYPE type that would be replaced by what needed:
#define STACK(TYPE) \
( \
struct stack \
{ \
size_t size; \
struct container *top; \
}; \
\
struct container \
{ \
TYPE data; \
struct container *next; \
}; \
\
struct stack *stack_init(void) \
{ \
struct stack *s = malloc(sizeof (struct stack)); \
if (!s) \
return NULL; \
return s; \
} \
... ...
)
This header file would be called in any .c file with this line
#include "utils_stack.h"
STACK(int)
Thing is, after trying every possible form of syntax gcc told me to try, I can't find a way to get it to work. I tried with parenthesis, brackets, both, none...
The code just simply won't work. Here is the error I get with the above syntax for example:
error: expected identifier or ‘(’ before ‘struct’
While trying to run gcc with the -E flag, I clearly see that TYPE is being replaced by int.
So here is my question, How do I need to write my macro to be able to... use it ?
Thank you in advance

As mentioned in the comment, this should work, just remove the parentheses:
#include <stdio.h>
#include <malloc.h>
#define STACK(TYPE) \
struct stack \
{ \
size_t size; \
struct container *top; \
}; \
\
struct container \
{ \
TYPE data; \
struct container *next; \
}; \
\
struct stack *stack_init(void) \
{ \
struct stack *s = malloc(sizeof (struct stack)); \
if (!s) \
return NULL; \
return s; \
} \
STACK(int)
int main()
{
struct stack *s;
s = stack_init();
// ...
}
Use parentheses if you define function-like macros, like:
#define maxint(a,b) \
({int _a = (a), _b = (b); _a > _b ? _a : _b; })
See gcc statement expresions for details.

Related

Parametrized generic C macros

I'm playing around with building a psuedo-generic type in C. Essentially, I'm trying to clone Rust's Option<T> with a predefined, constrained list of types allowable as T.
Obviously, C isn't really suited for this -- I'm doing this primarily to see how far I can go (as opposed to something I'd expect to use in real production code). To that end, any ugly hacks are fair game.
What I have so far builds out a separate set of inner-type-specific functions for all provided types. It looks something like this:
Header:
#pragma once
#define ALL_OPTIONS \
OPTION_INSTANCE(option_bool, bool) \
OPTION_INSTANCE(option_double, double) \
OPTION_INSTANCE(option_int, int)
#define OPTION_INSTANCE(name, inner) \
typedef struct { \
bool is_some; \
inner val; \
} name##_t;
ALL_OPTIONS
#undef OPTION_INSTANCE
#define OPTION_INSTANCE(name, inner) \
name##_t name##_some(inner val); \
name##_t name##_none(void); \
bool name##_is_some(name##_t self); \
bool name##_is_none(name##_t self); \
ALL_OPTIONS
#undef OPTION_INSTANCE
Implementation:
#include "option.h"
#define OPTION_INSTANCE(name, inner) \
name##_t name##_some(inner val) { \
return (name##_t) { \
.is_some = true, \
.val = val, \
}; \
} \
\
name##_t name##_none(void) { \
return (name##_t) { \
.is_some = false, \
}; \
} \
\
bool name##_is_some(name##_t self) { \
return self.is_some; \
} \
\
bool name##_is_none(name##_t self) { \
return !self.is_some; \
}
ALL_OPTIONS
#undef OPTION_INSTANCE
Note that in my actual code I have many more functions defined for the generated types.
This works well enough, though primarily all I've done is reduce implementation boilerplate. The next step would be to implement option_is_some (no type qualification) which can accept any option_<inner>_t
I can do that well enough with a manual macro, leveraging C11 generics:
#define option_is_some(self) \
_Generic((self), \
option_bool_t: option_bool_is_some, \
option_double_t: option_double_is_some, \
option_int_t: option_int_is_some, \
)(self)
but this necessarily duplicates the list of types defined in ALL_OPTIONS. What I'd really like to do would be something like
#define OPTION_INSTANCE(name, inner) \
name##_t: name##_is_some,
#define option_is_some(self) \
_Generic((self), \
ALL_OPTIONS \
default: false \
)(self)
#undef OPTION_INSTANCE
but that fails, since ALL_OPTIONS is expanded when option_is_some is used (where OPTION_INSTANCE will be undefined).
So, I'm looking for alternatives. I'd happily move to a radically different method of defining a generic list of types (instead of the ALL_OPTIONS hack) -- however, I do want to preserve the property that adding a new supported inner type only requires a change in a single location.
Just access the member in the macro itself:
#define option_is_some(self) ((self).is_some)
Overall, your implementation is strange. Do not have a central ALL_OPTIONS place - do one option at a time, separately from each other. Files are split into headers and source files in C.
#define OPTION_HEADER(name, inner) \
typedef struct { \
bool is_some; \
inner val; \
} name##_t; \
\
name##_t name##_some(inner val); \
name##_t name##_none(void); \
bool name##_is_some(name##_t self); \
bool name##_is_none(name##_t self);
#define OPTION_SOURCE(name, inner) \
name##_t name##_some(inner val) { \
return (name##_t) { \
.is_some = true, \
.val = val, \
}; \
} \
etc...
#define OPTION_HEADER_AND_SOURCE(name, ...) \
OPTION_HEADER(name, __VA_ARGS__)
OPTION_SOURCE(name, __VA_ARGS__)
Then you would just do the options:
OPTION_HEADER_AND_SOURCE(option_bool, bool)
OPTION_HEADER_AND_SOURCE(option_double, double)
OPTION_HEADER_AND_SOURCE(option_int, int)
You can take a look at other projects that I've found: https://github.com/tylov/STC and https://github.com/glouw/ctl that use macro-ish templates to implement in C various container known from C++.

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.

misra 19.10 with array initialiser

MISRA 19.10:
In the definition of a function-like macro each instance of a parameter shall be enclosed in parentheses unless it is used as the operand of # or ##.
I have a struct defined like this:
typedef struct
{
SUint_t affValueIndex;
const SFloat_t affLoSaturation;
const SFloat_t affHiSaturation;
const SFloat_t affCoeffTab[SDEF_ANALOG_FLOAT_FILTER_LEN];
SFloat_t affValueTab[SDEF_ANALOG_FLOAT_FILTER_LEN];
} SAnalogFloatFilter_t;
Then I do:
#define DEF_ANALOG_FILTER_COEFF_LIST {0.0287421759f, \
0.1225311874f, \
0.2123775504f, \
0.2726981726f, \
0.2123775504f, \
0.1225311874f, \
0.0287421759f}
#define SMK_ANALOG_FLOAT_FILTER_HANDLE(__name__, __coeff_list__, __hi_sat__, __low_sat__) \
SAnalogFloatFilter_t (__name__)[1] = {{0u, (__low_sat__), (__hi_sat__), __coeff_list__ , {(SFloat_t)0,}}}
static SMK_ANALOG_FLOAT_FILTER_HANDLE(CurrMonFilter,
DEF_ANALOG_FILTER_COEFF_LIST,
(SFloat_t)DEF_ANALOG_FILTER_HI_SAT,
(SFloat_t)DEF_ANALOG_FILTER_LO_SAT);
The problem is that the __ coeff_list __ parameter cannot have a parenthesis as it then expands to ({...}) (an array initialilser), to which the gcc complains:
foo.c:45:9: error: statement-expressions are not allowed outside functions nor in template-argument lists
Is there a clever way to keep the MISRA 19.10 check AND have an array initialiser in the SMK_ANALOG_FLOAT_FILTER_HANDLE macro?
This compiles for me:
typedef int SUint_t;
typedef float SFloat_t;
#define SDEF_ANALOG_FLOAT_FILTER_LEN 8
typedef struct
{
SUint_t affValueIndex;
const SFloat_t affLoSaturation;
const SFloat_t affHiSaturation;
const SFloat_t affCoeffTab[SDEF_ANALOG_FLOAT_FILTER_LEN];
SFloat_t affValueTab[SDEF_ANALOG_FLOAT_FILTER_LEN];
} SAnalogFloatFilter_t;
#define DEF_ANALOG_FILTER_COEFF_LIST (const SFloat_t[SDEF_ANALOG_FLOAT_FILTER_LEN]) \
{0.0287421759f, \
0.1225311874f, \
0.2123775504f, \
0.2726981726f, \
0.2123775504f, \
0.1225311874f, \
0.0287421759f}
#define SMK_ANALOG_FLOAT_FILTER_HANDLE(__name__, __coeff_list__, __hi_sat__, __low_sat__) \
SAnalogFloatFilter_t (__name__)[1] = {{0u, (__low_sat__), (__hi_sat__), (__coeff_list__) , {(SFloat_t)0,}}}
#define DEF_ANALOG_FILTER_HI_SAT 0.0f
#define DEF_ANALOG_FILTER_LO_SAT 0.0f
static SMK_ANALOG_FLOAT_FILTER_HANDLE(CurrMonFilter,
DEF_ANALOG_FILTER_COEFF_LIST,
(SFloat_t)DEF_ANALOG_FILTER_HI_SAT,
(SFloat_t)DEF_ANALOG_FILTER_LO_SAT);
Tested on Ubuntu 12.04.03 LTS with commands:
gcc-4.6 -c -o foo.o foo.c
and
gcc-4.8 -c -o foo.o foo.c

Is my modification in queue.h implemented by Berkeley right

the queue.h implemented by Berkeley in their FreeBSD is very useful indeed, now i got a question about the TAILQ_LAST macro, please note the difference i present
original code
#define TAILQ_HEAD(name, type) \
struct name
{ \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_ENTRY(type) \
struct
{ \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
my proposal
#define TAILQ_LAST(head, headname) \
((head)->tqh_last))
my point is that the tqh_last member of headname refers to the address of the tqe_next member of the last TAILQ_ENTRY, which is exactly the address of the last entry in the tailq.
please correct me if i am wrong. thanks in advance.
Just looking at the two definitions, I'd think that
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
will return a type* whereas this
#define TAILQ_LAST(head, headname) \
((head)->tqh_last))
will return a type**, so both are not equivalent.
No, they are not same. please note that tqh_last is addr of last next element, not last element.
If you directly use (head)->tqh_last, then it simply returns NULL.
Then why it is *(((struct headname *)((head)->tqh_last))->tqh_last)
Please look at:
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
} while (0)
(head)->tqh_last = &TAILQ_NEXT((elm), field);
and what we need is &TAILQ_NEXT((elm), field)->field.tqe_prev, according to (elm)->field.tqe_prev = (head)->tqh_last;, then we get
(*(((struct headname *)((head)->tqh_last))->tqh_last))

Problem definition of struct in Macro

I'm working on macros in C, trying to simulate the objet behavior but using C and I'm having a problem with the definition of a variable defined from a struct in another struct in a macro. That's my code... it works:
#include <stdio.h>
#include <stdlib.h>
#define STACK_MAX_CAPACITY 10
#define DECLARE_STACK(Type) \
typedef struct MetaPile_##Type; \
\
typedef struct Pile_##Type_t{ \
Type q[STACK_MAX_CAPACITY]; \
int pos; \
} Pile_##Type; \
\
typedef struct MetaPile_##Type_t{ \
void (* push) ( Pile_##Type* p, Type val ); \
void (*init) (Pile_##Type* p); \
} MetaPile_##Type; \
\
void init_##Type( Pile_##Type* p ){ \
p->pos = 0; \
int i; \
for(i=0; i<STACK_MAX_CAPACITY; i++){ \
p->q[i]=0; \
} \
} \
\
void push_##Type( Pile_##Type* p, Type val ) { \
if(p->pos < STACK_MAX_CAPACITY){ \
p->q[p->pos]=val; \
p->pos++; \
} \
} \
MetaPile_##Type TheMetaPile_##Type; \
void initTheMetaPile_##Type(){ \
TheMetaPile_##Type.init = &init_##Type; \
TheMetaPile_##Type.push = &push_##Type; \
} \
\
DECLARE_STACK(int)
int main(){
int i;
initTheMetaPile_int();
Pile_int pi;
TheMetaPile_int.init(&pi);
push_int(&pi, 2);
push_int(&pi, 3);
push_int(&pi, 4);
push_int(&pi, 5);
push_int(&pi, 6);
for(i=0; i<STACK_MAX_CAPACITY; i++){
printf("%d",pi.q[i]);
}
return 0;
}
The first structure define an array of a dinamic type thanks to the macro (Pile_##Type) that represents the attributs side of an objet, and another structure (MetaPile_##Type) that will manage the "methods" of the objet, via fonction pointers. The fonction init works as a constructor and initialises my "objet" pi.
Now what I want is to have a reference in Pile_##Type of a variable of type MetaPile_##Type (called for exemple myClass) in order to be able to make pi->myClass->push and call the fonction push_int. But when I make:
typedef struct Pile_##Type_t{ \
Type q[STACK_MAX_CAPACITY]; \
int pos; \
MetaPile_##Type myClass; \
} Pile_##Type; \
I have a misunderstandable mistake...
D:\main.c|40|warning: useless keyword or type name in empty declaration|
D:\main.c|40|error: syntax error before "MetaPile_int"|
D:\main.c|40|warning: no semicolon at end of struct or union|
D:\main.c|40|warning: type defaults to `int' in declaration of `Pile_int'|
D:\main.c|40|warning: data definition has no type or storage class|
D:\main.c|40|error: syntax error before '*' token|
D:\main.c|40|error: syntax error before '*' token|
D:\main.c|40|error: syntax error before '*' token|
D:\main.c||In function `init_int':|
D:\main.c|40|error: `p' undeclared (first use in this function)|
D:\main.c|40|error: (Each undeclared identifier is reported only once|
D:\main.c|40|error: for each function it appears in.)|
D:\main.c|40|error: syntax error before '*' token|
D:\main.c||In function `push_int':|
D:\main.c|40|error: `p' undeclared (first use in this function)|
D:\main.c|40|error: `val' undeclared (first use in this function)|
D:\main.c||In function `main':|
D:\main.c|47|error: syntax error before "pi"|
D:\main.c|49|error: `pi' undeclared (first use in this function)|
||=== Build finished: 12 errors, 4 warnings ===|
I don't know what's worong with the defintion of myClass, I've used * also but the error persits. Thanks if somebody can help.
Your problem is not the usage of macros, this only distracts you.
typedef struct MetaPile_int;
is just syntactically incorrect. A simple forward declaration of a struct looks like this:
struct MetaPile_int;
But if you just want to make your life easier do it like this:
typedef struct MetaPile_int MetaPile_int;
This is a forward declaration of the struct and a definition of the identifier MetaPile_int at the same time.
To get it working try it without putting it in a macro, first. Or use a compiler that helps you trace errors in macros such as clang.
Remove the typedef struct MetaPile_##Type; line - what's that supposed to do (besides causing your errors, that is)?
You try to insert a full struct (MetaPile_##Type) before declaring it, change the order of them like that [ in MetaPile_##Type you only use pointers to Pile_##Type_t, and the size of pointers is known]:
Edit:
This declaration works for me fine:
#define DECLARE_STACK(Type) \
struct Pile_##Type_t; \
\
typedef struct MetaPile_##Type_t{ \
void (* push) ( Pile_##Type_t* p, Type val ); \
void (*init) (Pile_##Type_t* p); \
} MetaPile_##Type; \
\
typedef struct Pile_##Type_t{ \
Type q[STACK_MAX_CAPACITY]; \
int pos; \
MetaPile_##Type myClass; \
} Pile_##Type; \
\
void init_##Type( Pile_##Type* p ){ \
p->pos = 0; \
int i; \
for(i=0; i<STACK_MAX_CAPACITY; i++){ \
p->q[i]=0; \
} \
} \
\
void push_##Type( Pile_##Type* p, Type val ) { \
if(p->pos < STACK_MAX_CAPACITY){ \
p->q[p->pos]=val; \
p->pos++; \
} \
} \
MetaPile_##Type TheMetaPile_##Type; \
void initTheMetaPile_##Type(){ \
TheMetaPile_##Type.init = &init_##Type; \
TheMetaPile_##Type.push = &push_##Type; \
} \
\
and it should do the work.

Resources