I have the following structure (simplified):
struct error_t{
const char *file;
const char *error_desc;
};
I wrote a macro to create the structure
#define ERROR_SET(error_desc) \
{ \
struct error_t tmp = {.error_desc = error_desc, .file = __FILE__}; \
struct error_t *ptr = malloc(sizeof(*ptr)); \
memcpy(ptr, &tmp, sizeof(tmp)); \
*error_ptr = ptr; \
}
The problem is that at the line
struct error_t tmp = {.error_desc = error_desc, .file = __FILE__}
both error_descs .error_desc = error_desc are replaced which is not what I wanted. The only solution I can see is to rename the macro function parameter from error_desc to _error_desc, but maybe there is a better way. Maybe we can sort of "escape" the error_desc to be substituted in the .error_desc?
Just do not use the same name for the parameter and the struct member
You can have a different MACRO that the preprocessor would replace as error_desc.
#define ERROR_DESC error_desc
Then you can define ERROR_SET like this:
#define ERROR_SET(error_desc) \
{ \
struct error_t tmp = {.ERROR_DESC = error_desc, .file = __FILE__}; \
struct error_t *ptr = malloc(sizeof(*ptr)); \
memcpy(ptr, &tmp, sizeof(tmp)); \
*error_ptr = ptr; \
}
This works because the substitution is done only once.
You can "deceive" the preprocessor with something like
#define CONCAT(a, b) a##b
#define ERROR_SET(error_desc) \
{ \
struct error_t tmp = { .CONCAT(error,_desc) = error_desc, .file = __FILE__ }; \
...\
}
but it is just not worth it. Just rename the parameter. And develop a convention for parameter naming that would help you to avoid such naming conflicts in the future.
On the second thought, the extra CONCAT macro is not even necessary. This will achieve the same objective
#define ERROR_SET(error_desc) \
{ \
struct error_t tmp = { .error##_desc = error_desc, .file = __FILE__ }; \
...\
}
Related
This question already has answers here:
What does a dot before the variable name in struct mean?
(2 answers)
Closed 7 hours ago.
I'm reading the source code iw and
I'm stucked in this struct.
I dont't understand what these code mean? (.handler = (_handler), etc...)
How can I understand that or any documents to learn that.
static struct cmd \
__cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden = {\
.name = (_name), \
.args = (_args), \
.cmd = (_nlcmd), \
.nl_msg_flags = (_flags), \
.hidden = (_hidden), \
.idby = (_idby), \
.handler = (_handler), \
.help = (_help), \
.parent = _section, \
.selector = (_sel), \
}; \
This is a macro that unfolds in a static structure.
#define __COMMAND(_section, _symname, _name, _args, _nlcmd, _flags, _hidden, _idby, _handler, _help, _sel)\
static struct cmd \
__cmd ## _ ## _symname ## _ ## _handler ## _ ## _nlcmd ## _ ## _idby ## _ ## _hidden\
__attribute__((used)) __attribute__((section("__cmd"))) = { \
.name = (_name), \
.args = (_args), \
.cmd = (_nlcmd), \
.nl_msg_flags = (_flags), \
.hidden = (_hidden), \
.idby = (_idby), \
.handler = (_handler), \
.help = (_help), \
.parent = _section, \
.selector = (_sel), \
}
If you take a look at the definition of cmd struct from iw/iw.h file, you would see that the handler member is a function pointer taking a whole bunch of parameters and returning int.
struct cmd {
const char *name;
const char *args;
const char *help;
const enum nl80211_commands cmd;
int nl_msg_flags;
int hidden;
const enum command_identify_by idby;
/*
* The handler should return a negative error code,
* zero on success, 1 if the arguments were wrong
* and the usage message should and 2 otherwise.
*/
int (*handler)(struct nl80211_state *state,
struct nl_cb *cb,
struct nl_msg *msg,
int argc, char **argv,
enum id_input id);
const struct cmd *(*selector)(int argc, char **argv);
const struct cmd *parent;
};
The macro initializes the struct assigning the provided function address to this pointer. The handler member now can be used as sort of interface for the struct and one may call the provided function via it.
I want to implement the Lisp Cons type in C, so I use link list to achieve it.
At the same time, I use a lot of macros to simpilfy the data creation.
The code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Macro Utils
*/
#define create_m(type) ((type *) malloc(sizeof(type)))
#define new_m(type, ...) ({ \
type * __t = create_m(type); \
*__t = (type){ __VA_ARGS__ }; \
__t; })
/*
* Type Define
*/
typedef struct atom Atom;
enum ATOM_TYPES;
// Cons Type
typedef Atom * Cons[2];
#define car(c) (c[0])
#define cdr(c) (c[1])
#define new_cons_m(car, cdr) ({ \
Cons * __c = create_m(Cons); \
car(__c) = car; \
cdr(__c) = cdr; })
// Id Type
typedef char * Id;
#define new_id_m(id) (strdup(id))
// Container Type
enum ATOM_TYPES {
ATOM_CONS, ATOM_ID
};
struct atom {
enum ATOM_TYPES type;
union {
Cons value_cons;
Id value_id;
void * value;
};
};
#define new_atom_m(t, ...) (new_m(Atom, .type = t, __VA_ARGS__))
#define new_atom_cons_m(car, cdr) ( \
new_atom_m(ATOM_CONS, .value_cons = new_cons_m(car, cdr)) )
#define new_atom_id_m(id) ( \
new_atom_m(ATOM_CONS, .value_id = new_id_m(id)) )
int main() {
printf("start program\n");
Atom * test = new_atom_cons_m(
new_atom_id_m("lisp"),
new_atom_cons_m(
new_atom_id_m("log"),
new_atom_id_m("say hello")
)
);
return 0;
}
And it failed to compile, with the following log:
arane.c: In function ‘main’:
arane.c:16:27: error: called object is not a function or function pointer
#define new_m(type, ...) ({ \
^
arane.c:18:18: note: in definition of macro ‘new_m’
*__t = (type){ __VA_ARGS__ }; \
^~~~~~~~~~~
arane.c:68:3: note: in expansion of macro ‘new_atom_m’
new_atom_m(ATOM_CONS, .value_cons = new_cons_m(car, cdr)) )
^~~~~~~~~~
arane.c:68:39: note: in expansion of macro ‘new_cons_m’
new_atom_m(ATOM_CONS, .value_cons = new_cons_m(car, cdr)) )
^~~~~~~~~~
arane.c:92:17: note: in expansion of macro ‘new_atom_cons_m’
Atom * test = new_atom_cons_m(
^~~~~~~~~~~~~~~
arane.c:66:29: note: in expansion of macro ‘new_m’
#define new_atom_m(t, ...) (new_m(Atom, .type = t, __VA_ARGS__))
^~~~~
arane.c:70:3: note: in expansion of macro ‘new_atom_m’
new_atom_m(ATOM_CONS, .value_id = new_id_m(id)) )
^~~~~~~~~~
arane.c:93:5: note: in expansion of macro ‘new_atom_id_m’
new_atom_id_m("lisp"),
^~~~~~~~~~~~~
...and much more errors
I think it is because there are some expressions in function call's argument list. I am seeking for some way to solve it, I use gcc7.5 to finish my work, if needed, I can upgrade it.
-----------2022-01-24-14:15-----------
The problem is solved, with some twest in code, however, I still don't really understand how it was happend.
The code changed as below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* Macro Utils
*/
#define create_m(type) ((type *) malloc(sizeof(type)))
#define new_m(type, ...) ({ \
type * __t = create_m(type); \
*__t = (type){ __VA_ARGS__ }; \
__t; })
/*
* Type Define
*/
typedef struct atom Atom;
enum ATOM_TYPES;
// Cons Type
typedef Atom * Cons[2];
#define car(c) (c[0])
#define cdr(c) (c[1]) // deletes here
// Id Type
typedef char * Id;
#define new_id_m(id) (strdup(id))
// Container Type
enum ATOM_TYPES {
ATOM_CONS, ATOM_ID
};
struct atom {
enum ATOM_TYPES type;
union {
Cons value_cons;
Id value_id;
void * value;
};
};
#define new_atom_m(t, ...) (new_m(Atom, .type = t, __VA_ARGS__))
#define new_atom_cons_m(car, cdr) ( \
new_atom_m(ATOM_CONS, .value_cons[0] = car, .value_cons[1] = cdr) )
#define new_atom_id_m(id) ( \ // changes here
new_atom_m(ATOM_CONS, .value_id = new_id_m(id)) )
int main() {
printf("start program\n");
Atom * test = new_atom_cons_m(
new_atom_id_m("lisp"),
new_atom_cons_m(
new_atom_id_m("log"),
new_atom_id_m("say hello")
)
);
// Atom * test = new_atom_cons_m(NULL, NULL);
return 0;
}
Let's say I have Stack that I want to use to store various different types. If I define the interface as follows:
// stack.h
typedef struct Stack {
size
push // function pointers
pop
etc.
};
And let's say I want to support two different stack types, and so I create:
// stack.c
Stack person_stack;
person_stack->push = push_to_person_stack;
Stack animal_stack;
animal_stack->push = push_to_animal_stack;
How can I make it such that the push_to_<type>_stack is effectively private and the caller of that stack is only able to see the Stack->push function? Or maybe that's not possible in C and you need an OO language to do it, but what would be an example of having a unified interface for this?
You can use function pointers to emulate methods in other OOP languages but still you need to pass the instance to the method otherwise there is no way to know on which stack to push. Also using void* would make more problems than it solves.
struct Stack {
void (*push)(Stack* self, void* data); //< self here
}
Here is a way that I use to emulate template/generics in c by using macros (reference : https://github.com/wren-lang/wren/blob/main/src/vm/wren_utils.h#L16)
#define DECLARE_STACK(type) \
typedef struct { \
type* data; \
int size; \
int capacity; \
} type##Stack; \
void type##Stack_push(type##Stack* self, type value); \
type type##Stack_pop(type##Stack* self); \
void type##Stack_init(type##Stack* self); \
#define DEFINE_STACK(type) \
void type##Stack_push(type##Stack* self, type value) { \
if (self->capacity <= self->size + 1) { \
self->capacity = self->capacity * 2; \
self->data = realloc(self->data, sizeof(type) * self->capacity); \
} \
self->data[self->size] = value; \
self->size++; \
} \
\
type type##Stack_pop(type##Stack* self) { \
self->size--; \
return self->data[self->size]; \
} \
\
void type##Stack_init(type##Stack* self) { \
self->size = 0; \
self->capacity = 2; \
self->data = malloc(sizeof(type) * self->capacity); \
} \
typedef struct Person {
int id;
} Person;
DECLARE_STACK(Person); // in person.h
DEFINE_STACK(Person); // in person.c
int main() {
Person p1, p2, p3, p4;
p1.id = 1; p2.id = 2; p3.id = 3; p4.id = 4;
PersonStack stack;
PersonStack_init(&stack);
PersonStack_push(&stack, p1);
PersonStack_push(&stack, p2);
PersonStack_push(&stack, p3);
Person p;
p = PersonStack_pop(&stack); // p.id = 3
p = PersonStack_pop(&stack); // p.id = 2
PersonStack_push(&stack, p4);
p = PersonStack_pop(&stack); // p.id = 4
p = PersonStack_pop(&stack); // p.id = 1
return 0;
}
And If you want to debug, macros are harder to debug the flow with a debugger, so I've used a python script to generate the expansion of the macro to source and header files before compile (I build with scons which is python based so I automated the source files generation)
I am trying to define a macro -
#define macro1(arg1) \
do{ \
int _state = 0; \
if (arg1 && arg1->member_) \
_state = arg1->member_->state_; \
printf("%d", _state); \
} while(0)
A *a = new A():
macro1(a); // Works
macro1(NULL); // Error
The specific error I see is -
"error: base operand of ‘->’ is not a pointer"
Aren't we allowed to pass NULL as an argument to macros?
Macro expansion is just text replacement, so when you passed NULL, it will expand to NULL->member, clearly it is an error. One way is to use a temporary variable for that:
#define macro1(arg1) \
do{ \
A* p = (arg1);
int _state = 0; \
if (p && p->member_) \
_state = p->member_->state_; \
printf("%d", _state); \
} while(0)
A *a = new A():
macro1(a);
macro1(NULL);
This way both cases will work.
You have to understand what's a macro in order to understand your mistake. Except for the compiler, there's an animal called pre-compiler. It replaces all the macros' references by the actual code defined for this macro. So this code:
#define macro1(arg1) \
do{ \
int _state = 0; \
if (arg1 && arg1->member_) \
_state = arg1->member_->state_; \
printf("%d", _state); \
} while(0)
A *a = new A():
macro1(a); // Works
macro1(NULL); // Error
will be replaced with:
A *a = new A():
do{
int _state = 0;
if (a && a->member_)
_state = a->member_->state_;
printf("%d", _state);
} while(0)
do{
int _state = 0;
if (NULL && NULL->member_)
_state = NULL->member_->state_;
printf("%d", _state);
} while(0)
THIS code will be compiled. And now you can see for yourself what's the root cause of the compilation error.
Macros are just a text replacement.
for example, if you have
#define mac(x) x/x
that would work for must numbers but not for 0, because it will be replaced with 0/0 which is not defined.
in your case if you pass NULL it will be replaced with:
do{ \
int _state = 0; \
if (NULL && NULL->member_) \
_state = NULL ->member_->state_; \
printf("%d", _state); \
} while(0)
so what is the meaning of NULL->member_ in this case. No sense, hence it fails.
consider using a regular function, or two macros one for regular pointers and one for NULL pointers, and make your code as this:
if (ptr)
macro1(ptr);
else
macro2;
Small adjust let the pre-compiler know the type size + a forward declaration and it'll work:
#define macro1(arg1) \
do{ \
int _state = 0; \
if ((arg1) && ((A*)arg1)->member_) \
_state = ((A*)arg1)->member_->state_; \
printf("%d", _state); \
} while(0)
Complete code:
#include <stdio.h>
class A;
#define macro1(arg1) \
do{ \
int _state = 0; \
if ((arg1) && ((A*)arg1)->member_) \
_state = ((A*)arg1)->member_->state_; \
printf("%d", _state); \
} while(0)
struct member{
int state_;
};
class A {
public:
member* member_;
};
int main(int n, char** arg) {
A* a = new A();
a->member_ = new member();
a->member_->state_ = 1;
macro1(a);
macro1(NULL);
return 0;
}
The more fundamental problem is that NULL is not a pointer, it is a macro for 0.
Hence when you pass in NULL, it is equivalent to passing in 0, which of course is an error.
As other answers have mentioned, giving the argument an explicit cast will fix it
(A*)arg1
As a side note, you should be using nullptr in C++ for a null pointer.
EDIT: As #AjayBrahmakshatriya pointed out, NULL can be defined as (void*)0 (in C only) which will be a pointer, but the argument still holds true, NULL is not a pointer of your type.
EDIT2: Apparently in C++11 and later, NULL can be defined as nullptr
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.