Problem definition of struct in Macro - c

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.

Related

Generating function declarations and vtables for different types through x-macros in C

I'm trying to generate a bunch of types off a simple template using macros to remove some of the copy and paste work this would usually require but I've ran into a bit of a problem.
These are my macros to generate the types:
#define VEC2_TYPES_LIST(X) \
X(Vec2f, float, ) \
X(Vec2d, double, ) \
X(Vec2u, uint32_t, ) \
X(Vec2i, int32_t, )
#define X_TYPE(u, t, s) \
typedef union u \
{ \
struct \
{ \
t x; \
t y; \
}; \
\
struct \
{ \
t elem[2]; \
}; \
\
s \
} u;
VEC2_TYPES_LIST(X_TYPE)
The problem is that I want to create common functions to these types that will be dynamically dispatched at runtime through a vtable. So as well as making the function definitions I also wanted to put them into a structure as function pointers. Something like this:
#define VEC2_FUNCTIONS_LIST( ?? )
X(u, u##_add, (u a, u b)) // return type, function name, params
To generate this code:
Vec2f vec2f_add(Vec2f a, Vec2f b);
...
Vec2i vec2i_add(Vec2i a, Vec2i b);
struct Vec2fVTable
{
Vec2f (*vec2f_add)(Vec2f a, Vec2f b);
};
// same for other types
I have no idea how to go about doing this so I'd appreciate if someone could teach me.
I have found a solution:
// Generate export functions and function pointers for the vtables
#define X_FUNC(ret, name, param) ACC_EXPORT ret name param;
#define X_FUNC_PTR(ret, name, param) ret (*name) param;
// Generate types
#ifdef X86_SIMD
#define VEC_TYPE_LIST(X) \
VEC_DIMENSIONS(X, f, float, __m128 simd;) \
VEC_DIMENSIONS(X, d, double, __m128d simd;) \
VEC_DIMENSIONS(X, i, int32_t, __m128i simd;) \
VEC_DIMENSIONS(X, u, uint32_t, __m128i simd;)
#else
#define VEC_TYPE_LIST(X) \
VEC_DIMENSIONS(X, f, float, ) \
VEC_DIMENSIONS(X, d, double, ) \
VEC_DIMENSIONS(X, i, int32_t, ) \
VEC_DIMENSIONS(X, u, uint32_t, )
#endif
// Generate dimensions
#define VEC_DIMENSIONS(X, suf, type, simd) \
X(suf, 2, type, simd) \
X(suf, 3, type, simd) \
X(suf, 4, type, simd)
// Generate element structs
#define VEC_ELEMENTS_STRUCT_2(type) struct { type x; type y; };
#define VEC_ELEMENTS_STRUCT_3(type) struct { type x; type y; type z; };
#define VEC_ELEMENTS_STRUCT_4(type) struct { type x; type y; type z; type w; };
// Generate functions
#define VEC_FUNCTIONS_LIST(X, funcPref, type, vecType) \
X(vecType, funcPref##_add, (vecType a, vecType b)) \
X(vecType, funcPref##_subtract, (vecType a, vecType b)) \
// Type template
#define X_VEC_TYPE(suf, dim, type, simd) \
typedef union Vec##dim##suf \
{ \
VEC_ELEMENTS_STRUCT_##dim(type) \
struct { type elements[dim]; }; \
simd \
} Vec##dim##suf; \
VEC_FUNCTIONS_LIST(X_FUNC, vec##dim##suf, type, Vec##dim##suf) \
typedef struct Vec##dim##suf##VTable \
{ \
VEC_FUNCTIONS_LIST(X_FUNC_PTR, vec##dim##suf, type, Vec##dim##suf) \
} Vec##dim##suf##VTable; \
// Generate everything
VEC_TYPE_LIST(X_VEC_TYPE)

Parameter of macro mixed with field of structure

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\
}

Token Pasting Confusion

all
My codes like this:
#define TTP_ROUTE_TABLE_ENTRY_INC(table) \
static inline void \
ttp_route_##table_inc(void) \
{ \
cur_l3_##table_table_entries++; \
}
TTP_ROUTE_TABLE_ENTRY_INC(ipv4_host)
TTP_ROUTE_TABLE_ENTRY_INC(ipv4_route)
TTP_ROUTE_TABLE_ENTRY_INC(ipv6_host)
TTP_ROUTE_TABLE_ENTRY_INC(ipv6_route)
#undef TTP_ROUTE_TABLE_ENTRY_INC
but gcc warning:
lib/ttp-route-table.c:130:1: error: redefinition of 'ttp_route_table_inc'
So I think GCC preprocess ##table into table, actually I want
TTP_ROUTE_TABLE_ENTRY_INC(ipv4_host)
will be translate into this:
static inline void \
ttp_route_ipv4_host_inc(void) \
{ \
cur_l3_ipv4_host_table_entries++; \
}
So I don't know what's wrong with my codes. Thank you for your help.
You need another set of # after the argument table:
ttp_route_##table##_inc(void)
The same goes for other lines containing table.

Generic multiline macro with parameters

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.

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.

Resources