The space itself does nothing, since spaces are used to separate pre-processor tokens and the macro is pre-processed after that's done. So you can add as many spaces as you like.
The only issue is that you can't violate the syntax, so this classic mistake won't compile:
#define A (B, C) ... // bad syntax, space between macro name and parameter list
#define A(B, C) ... // ok
So yes you can write something obscure like
#define define_int(a) int a;
...
define_int(*const a);
or
define_int(* const a );
and get the type int*const a;
.
Why you would ever want to write such horrible code, I have no idea. Inventing your own secret macro language in C is one of them royally stupid things.
Regarding the edit of inventing something like ASSIGN(A, return B)
for a return from function macro with some clean-up code, different flavours of such macros are both commonly-used and naive.
The proper way to centralize clean-up in a function when you need to return from multiple places is this (pseudo code):
void wrapper (void)
{
something a = allocate_stuff();
error result = the_actual_function(a);
if(result == whatever)
do_that();
cleanup(a);
}
inline error the_actual_function (something a)
{
...
if(bad)
{
return error_42;
}
}
This design pattern reduces clutter inside the actual function, when you only need to return upon error. It also gets rid of "BASIC style" on error goto, which is another rather naive way of writing error handlers.