Is there a way to use the _Generic keyword multiple times in the same expression to create a single string literal?
What I am looking for is a way to for example generate a single format string to pass to printf, with all the conversion specifiers adapted to the proper types.
When writing this answer I ended up with a rather ugly work-around:
#include <stdio.h>
typedef struct {
int a;
char b;
long c;
} ABC;
// printf conversion specifiers:
#define CS(x) \
_Generic((x), \
int: "%d", \
char: "%c", \
long: "%ld")
int main (void)
{
ABC abc = {1, 'a', 2};
printf(CS(abc.a), abc.a); printf(" ");
printf(CS(abc.b), abc.b); printf(" ");
printf(CS(abc.c), abc.c); printf(" ");
return 0;
}
6 printf calls instead of 1, hardly ideal.
The problem is that I can't find a way to combine _Generic and string literal concatenation by the pre-processor, like this:
printf(CS(abc.a) " ", abc.a); // doesnt work
printf(CS(abc.a) CS(abc.b), abc.a, abc.b); // doesnt work either
Because apparently generic macros don't count as string literals in the pre-processor, so string literal concatenation isn't possible. I toyed around with "stringification" macros but no luck there.
I'm going to say that the answer is NO.
First, the _Generic keyword is not (and cannot possibly be) a pre-processor directive. A generic-selection is a primary expression, as defined in section 6.5.1. Given the input
printf(CS(abc.a) "hello", abc.a);
the output from the preprocessor (generated by the -E compiler option) is:
printf(_Generic((abc.a), int: "%d", char: "%c", long: "%ld") "hello", abc.a);
Notice that string concatenation is not possible because the generic-selection has not been evaluated. Also note that it's impossible for the pre-processor to evaluate since it requires knowledge that abc is a structure of type ABC, that has member a. The pre-processor does simple text substitution, it has no knowledge of such things.
Second, the compiler phases defined in section 5.1.1.2 don't allow evaluation of _Generic keywords before string concatenation. The relevant phases, quoted from the spec, are
Adjacent string literal tokens are concatenated.
White-space characters separating tokens are no longer significant. Each preprocessing token is converted into a token. The resulting
tokens are syntactically and semantically analyzed and translated as a
translation unit.
The _Generic keyword must be evaluated in phase 7, since it requires knowledge that is only available after tokens have been syntactically and semantically analyzed, e.g. that abc is a structure with member a. Hence, multiple _Generic keywords cannot take advantage of string concatenation to produce a single string literal.
Nice question, you can paste a string passing another parameter:
#include <stdio.h>
typedef struct {
int a;
char b;
long c;
} ABC;
// printf conversion specifiers:
#define CS2(x, y) \
_Generic((x), \
int: "%d" y, \
char: "%c" y, \
long: "%ld" y)
int main (void)
{
ABC abc = {1, 'a', 2};
printf(CS2(abc.a, "Hello"), abc.a);
return 0;
}
Just for the record, it turns out it is possible to generate a string constant based on _Generic at compile-time, by using other dirty tricks than those available from the pre-processor.
The solution I came up with is so ugly that I barely dare to post it, but I'll do so just to prove it possible.
Don't write code like this!
#include <stdio.h>
typedef struct {
int a;
char b;
long c;
} ABC;
// printf conversion specifiers:
#define CS(x) \
_Generic((x), \
int: "%d", \
char: "%c", \
long: "%ld")
#pragma pack(push, 1)
#define print2(arg1,arg2) \
{ \
typedef struct \
{ \
char arr1 [sizeof(CS(arg1))-1]; \
char space; \
char arr2 [sizeof(CS(arg2))-1]; \
char nl_nul[2]; \
} struct_t; \
\
typedef union \
{ \
struct_t struc; \
char arr [sizeof(struct_t)]; \
} cs2_t; \
\
const cs2_t cs2 = \
{ \
.struc.arr1 = CS(arg1), \
.struc.space = ' ', \
.struc.arr2 = CS(arg2), \
.struc.nl_nul = "\n" \
}; \
\
printf(cs2.arr, arg1, arg2); \
}
#pragma pack(pop)
int main (void)
{
ABC abc = {1, 'a', 2};
print2(abc.a, abc.b);
print2(abc.a, abc.c);
print2(abc.b, abc.c);
return 0;
}
Output:
1 a
1 2
a 2
Explanation:
The macro print2 is a wrapper around printf and prints exactly 2 arguments, no matter type, with their correct conversion specifiers.
It builds up a string based on a struct, to which the conversion specifier string literals are passed. Each array place-holder for such a conversion specifier was purposely declared too small to fit the null termination.
Finally, this struct is dumped into a union which can interpret the whole struct as a single string. Of course this is quite questionable practice (even though it doesn't violate strict aliasing): if there is any padding then the program will fail.
Related
So, I am familiar with nested macros.
Now, I want to change a macro first changed by _Generic with some other macro like:
#include<stdio.h>
#define some_func(X) _Generic((X), \
char* : some_func_char, \
default : some_func_default)(X)
#define some_func_char(X) some_func_char(X, sizeof(X)/ sizeof(char))
void (some_func_char)(char *blah, size_t len_blah)
{
// do something
}
void some_func_default(double blah)
{
// code
}
int main()
{
some_func("hello");
return 0;
}
but it is raising a error as
main.c: In function ‘main’:
main.c:5:22: error: too few arguments to function ‘some_func_char’
5 | #define some_func(X) _Generic((X), \
| ^~~~~~~~
main.c:22:3: note: in expansion of macro ‘some_func’
22 | some_func("hello");
| ^~~~~~~~~
main.c:10:7: note: declared here
10 | void (some_func_char)(char *blah, size_t len_blah)
| ^~~~~~~~~~~~~~
some_func_char is calling the function not the macro in the _Generic call (even trying to stop the expansion with the parenthesis), on the other hand, you can not ommit the second parameter in some_func_default if some_func_char expects two parameters, switch to:
#include <stdio.h>
#define some_func(X) _Generic((X), \
char *: some_func_char, \
default: some_func_default)(X, sizeof X)
void some_func_char(char *blah, size_t len_blah)
{
// do something
}
void some_func_default(double blah, size_t dummy)
{
(void)dummy;
// code
}
int main()
{
some_func("hello");
return 0;
}
or better yet:
#include <stdio.h>
#include <string.h>
#define some_func(X) _Generic((X), \
char *: some_func_char, \
default: some_func_default)(X)
void some_func_char(char *blah)
{
size_t len = strlen(blah);
// do something
}
void some_func_default(double blah)
{
// code
}
int main()
{
some_func("hello");
return 0;
}
This second version allows you to pass and compute the correct length also for a pointer to char, don't worry for the performance, strlen is very fast.
Also, notice that sizeof(char) is always 1
It is important to understand that although generic selection is not really useful except in conjunction with macros, it is not itself interpreted by the preprocessor. Consider, then, this statement:
some_func("hello");
Where that appears in the example code, a definition of some_func as the identifier of a function-like macro is in scope, and the expansion of that macro produces this, prior to rescanning:
_Generic(("hello"), char *: some_func_char, default: some_func_default)("hello")
The preprocessor then scans that for further macro replacements, but again, _Generic is not a macro, and it has no other special significance to the preprocessor. There is an in-scope definition of some_func_char as the identifier of a function-like macro, but the appearance of that identifier in the above line does not match it because it is not followed by an open parenthesis. Nothing else in that line is significant (in context) to the preprocessor either, so that's in fact the final preprocessed form.
Now observe that the expression ("hello") matches the char * alternative of the generic selection expression, so the function identifier some_func_char is the selected result, but the parenthesized argument list ("hello") does not contain the correct number of arguments for that function. The overall expression is a more complicated variation on trying to call (some_func_char)("hello"). The some_func_char() macro never comes into play.
It should be clear, now, that you cannot use generic selection to select function identifiers of functions that take different numbers of arguments. But of course you can use it to select different function calls. For example,
#define some_func(X) _Generic( \
(X), \
char *: some_func_char((X), sizeof (X)), \
default: some_func_default(X) \
)
void some_func_char(char *s, size_t z) { }
void some_func_default(void *p) { }
int main(void) {
some_func("hello");
}
In a previous question I found a way to overload functions in C99 when each function only took a single argument. See the answers in: Function overloading in C using GCC - compiler warnings for details.
Now that I've found a way to do it with single argument functions I'm wondering how this can be done for functions that take multiple arguments. I assume it will have something to do with __VA_ARGS__ and using ... but I can't seem to find anything that works or even wants to compile.
This will work for a print that takes 2 arguments:
#define print(x, y) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int) && \
__builtin_types_compatible_p(typeof(y), int), print_int, \
(void)0)(x, y)
But if I also want another version that takes one argument I can't redefine it. Adding this will give me an error saying print is redefined:
#define print(x) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string, \
(void)0)(x)
How can I overload print so it will work with 2 integers as an input or with a character array?
example usage:
print(1, 2);
print("this");
Or even better... how can I make it work with any combination of types or any number of arguments?
Also remember, since this is C99 the _Generic keyword is not available.
You can do what you want with GCC's extensions and with an overdose of preprocessor tricks. The commenters have already made their opinion clear: C is rather explicit and has a one-to-one relationship with the symbols produced. If you want function overloading and type inspection, use one of the many languages that provide them.
Baroque macro solutions tend to be toys rather than code that's suitable for production, but it's still an interesting exercise to push the envelope. Safety helemts on, though, and be aware that:
... the solution isn't portable, because the core gimmick of choosing arguments via types is already GCC specific.
... the solution is build on macros. Finding syntax errors in macros is difficult, because the error messages refer to expanded code that the user doesn't see.
... the solution pollutes the namespace with many macro names. If you really want to use this solution, prefix all your macros (except the most visible ones) consistenty as to minimize the danger of symbol collision.
That out of the way, let's implement a function put that writes its arguments to stdin according to its type:
const char *name = "Fred";
double C = 12.5;
put(1, " ", 2); // 1 2
put("Hello, I'm ", name, "!"); // Hello, I'm Fred!
put(C, " Celsius"); // 12.5 Celsius
put(C * 1.8 + 32.0, " Fahrenheit"); // 54.5 Fahrenheit
For the sake of simplicity, the solution accepts only up to three arguments of either int, const char * or double, but the maximum number of arguments is extensible.
The solution consists of these parts:
Variadic constant-type macros
Say you want to have a function that sums all arguments. The number of arguments may vary, but all arguments are of type double. If they are not of type double, they should be promoted to double.
Variadic functions aren't a good solution, because they will pass the arguments to the function per individual type. trying to sum(1, 2, 3) as double will have disastrous results.
Instead, you can use compound literals to create an array of doubles on the fly. Use the sizeof mechanism to get the length of the array. (The arguments may have side effects, because the array inside the sizeof isn't evaluated, only its size is determined.)
#define sum(...) sum_impl(sizeof((double[]){__VA_ARGS__})/ \
sizeof(double), (double[]){__VA_ARGS__})
double sum_impl(size_t n, double x[])
{
double s = 0.0;
while (n--) s += x[n];
return s;
}
This will yield 6.0 for sum(1, 2, 3) in a calculation performed on doubles.
Variant type
You want all arguments to be of the same type, but this type should be able to represent all supported types of your function. The C way to create a variant is to use a tagged union, a union inside a struct:
typedef struct var_t var_t;
struct var_t {
int type;
union {
int i;
double f;
const char *s;
} data;
};
The type could be an enumeration. I use charcter constants according the to printf formats here.
The variant of an expression is determined with a macro VAR, which is essentially the gcc specific you have posted above:
#define CHOOSE __builtin_choose_expr
#define IFTYPE(X, T) __builtin_types_compatible_p(typeof(X), T)
#define VAR(X) \
CHOOSE(IFTYPE(X, int), make_var_i, \
CHOOSE(IFTYPE(X, const char[]), make_var_s, \
CHOOSE(IFTYPE(X, const char *), make_var_s, \
CHOOSE(IFTYPE(X, double), make_var_f, \
make_var_0))))(X)
The macro invokes any of the make_var functions. These functions must be defined for each valid type:
var_t make_var_i(int X) { var_t v = {'i', {.i = X}}; return v; }
var_t make_var_s(const char *X) { var_t v = {'s', {.s = X}}; return v; }
var_t make_var_f(double X) { var_t v = {'f', {.f = X}}; return v; }
var_t make_var_0() { var_t v = {'#'}; return v; }
Incorporating the X into the type-dependent expression doesn't work, as you have already found out. Neither can you use compound literals with designated initialisers here, probably for the same reasons. (I've said that error checking with macros is hard, haven't I?)
This is the only GCC specific part; it could also be achieved with C11's _Generic.
Applying the macro to all arguments of a function
You must apply the VAR macro to all arguments of your variadic put macro. You cannot process the head of the variadic arguments until you get an empty list, because you cannot expand macros recursively, but you can use a trick that counts the arguments to the macro and then expand to a macro that takes that many arguments:
#define PUT1(_1) put_impl(1, (var_t[]){VAR(_1)})
#define PUT2(_1, _2) put_impl(2, (var_t[]){VAR(_1), VAR(_2)})
#define PUT3(_1, _2, _3) put_impl(3, (var_t[]){VAR(_1), VAR(_2), VAR(_3)})
#define SELECT_N(_1, _2, _3, N, ...) N
#define put(...) SELECT_N(__VA_ARGS__, PUT3, PUT2, PUT1)(__VA_ARGS__)
Now put takes 1, 2 or 3 arguments. If you provide more than 3, you get an obscure error message that doesn't have anything to do with not providing too many arguments.
The code above will not accept an empty argument list. With the GCC entension , ##__VA_ARGS, which will write a comma only if the variadicargument list isn't empty, you can extend this to:
#define PUT0() put_impl(0, NULL)
#define PUT1(_1) put_impl(1, (var_t[]){VAR(_1)})
#define PUT2(_1, _2) put_impl(2, (var_t[]){VAR(_1), VAR(_2)})
#define PUT3(_1, _2, _3) put_impl(3, (var_t[]){VAR(_1), VAR(_2), VAR(_3)})
#define SELECT_N(X, _1, _2, _3, N, ...) N
#define put(...) SELECT_N(X, ##__VA_ARGS__, PUT3, PUT2, PUT1,PUT0)(__VA_ARGS__)
You can extend this solution to arbitrarily many arguments if you like.
The implementation
The above macro invokes the function put_impl, which is the implementation of how to print an array of n variants. After all the tricks above, the functions is rather straightforward:
void put_impl(size_t n, const var_t var[])
{
for (size_t i = 0; i < n; i++) {
switch(var[i].type) {
case 'i': printf("%i", var[i].data.i); break;
case 'f': printf("%g", var[i].data.f); break;
case 's': printf("%s", var[i].data.s); break;
case '#': printf("[undef]"); break;
}
}
putchar('\n');
}
Putting it all together
The following program uses the method described above to print some rather silly stuff. It is not portable, but runs if compiled with gcc -std=gnu99:
#include <stdlib.h>
#include <stdio.h>
#define CHOOSE __builtin_choose_expr
#define IFTYPE(X, T) __builtin_types_compatible_p(typeof(X), T)
#define VAR(X) \
CHOOSE(IFTYPE(X, int), make_var_i, \
CHOOSE(IFTYPE(X, const char[]), make_var_s, \
CHOOSE(IFTYPE(X, const char *), make_var_s, \
CHOOSE(IFTYPE(X, double), make_var_f, \
make_var_0))))(X)
#define PUT0() put_impl(0, NULL)
#define PUT1(_1) put_impl(1, (var_t[]){VAR(_1)})
#define PUT2(_1, _2) put_impl(2, (var_t[]){VAR(_1), VAR(_2)})
#define PUT3(_1, _2, _3) put_impl(3, (var_t[]){VAR(_1), VAR(_2), VAR(_3)})
#define SELECT_N(X, _1, _2, _3, N, ...) N
#define put(...) SELECT_N(X, ##__VA_ARGS__, PUT3, PUT2, PUT1,PUT0)(__VA_ARGS__)
typedef struct var_t var_t;
struct var_t {
int type;
union {
int i;
double f;
const char *s;
} data;
};
var_t make_var_i(int X) { var_t v = {'i', {.i = X}}; return v; }
var_t make_var_s(const char *X) { var_t v = {'s', {.s = X}}; return v; }
var_t make_var_f(double X) { var_t v = {'f', {.f = X}}; return v; }
var_t make_var_0() { var_t v = {'#'}; return v; }
void put_impl(size_t n, const var_t var[])
{
for (size_t i = 0; i < n; i++) {
switch(var[i].type) {
case 'i': printf("%i", var[i].data.i); break;
case 'f': printf("%g", var[i].data.f); break;
case 's': printf("%s", var[i].data.s); break;
case '#': printf("[undef]"); break;
}
}
putchar('\n');
}
int main()
{
const char *name = "Fred";
double C = 12.5;
put(1, " ", 2);
put("Hello, I'm ", name, "!");
put();
put(C, " Celsius");
put(C * 1.8 + 32.0, " Fahrenheit");
return 0;
}
You can go crazy on the types and number of arguments you want to support, but keep inn mind that the bigger your jungle of macros gets, the harder it will be to maintain and to debug.
This solution is in no way generic, but it will get the job done for the very specific case asked in the question.
#include <stdio.h>
#define print(...) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(FIRST(__VA_ARGS__)), int), print_int, print_string)\
(__VA_ARGS__)
#define FIRST(A, ...) A
void print_int(int i, int j) {
printf("int: %d %d\n", i, j);
}
void print_string(char* s) {
printf("char*: %s\n", s);
}
int main(int argc, char* argv[]) {
print(1, 2);
print("this");
return 0;
}
If anyone can find a more generalized solution that will work consistently when new overloads are added that would be greatly appreciated.
Is it possible to expand a macro which accepts multiple arguments to a different macro if first argument is not the expected value
E.g
int main()
{
PRINT(2, "%d%d\n", i, j); //should expand to syslog(2, "%d%d\n", i, j)
PRINT("%d%d\n", i, j); //arg1 which is expected to be an int is not preset.
/* This should expand differently may be to a default level say 3. syslog(3, "%d%d\n", i,j); */
}
I would have tried this kind of over loading if I knew total number of args.
I really recommend to write two separate macros for this, just as you would write two differently named functions for the two signatues in C. (I would rather write macros that tell you what level they are explicitly, like ERROR(...), WARNING(..) etc. than introduce a default argument.)
That said, there are two possibilities to achieve what you want.
C11 _Generic selections
The _Generic keyword was introduced with C11. It allows to expand macros in a switch-like manner according to the type of an argument; Robert Gamble has a good introduction.
You want to distinguish two cases: First argument is a string and first argument is an integer. A drawback is that in _Generic, a string literal isn't treated as char * or const char *, but as char[size]. For example, "%d" is a char[3].
In your case, we can get around this by treating a string as anything that isn't an integer. The compiler will sort out all non-string, non-integer arguments later. So:
#define PRINT(fmt, ...) \
_Generic(fmt, \
int: syslog(fmt, __VA_ARGS__), \
default: syslog(3, fmt, __VA_ARGS__))
There are drawbacks: You can't have a single-argument call, because that would leave a comma in the call. (gcc's ##__VA_ARGS__ gets around that.) And the _Generic keyword is not yet widely implemented; this solution will make your code highly unportable.
String introspection hack
Ordinary C99 macros have no information on their type. C code can make a guess, however. Here's an example that checks whether a macro argument is a string literal:
#define PRINT(sev, ...) \
if (#sev[0] == '"') syslog(3, sev, __VA_ARGS); \
else syslog(sev, __VA_ARGS__);
This works -- almost. The compiler will probably compile the constant condition away and only gererate code for one of the branches. But it will parse the branches anyway and the dead branch will have a wrong function signature, which will generate warnings.
You can get around this by writing a variadic front-end function in C. Here's an example that works:
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#define HEAD(X, ...) X
#define STR_(x) #x
#define STR(x) STR_(x)
#define PRINT(...) \
msg(*STR(HEAD(__VA_ARGS__)) == '"', __VA_ARGS__)
int msg(int dflt, ...)
{
va_list va;
int sev = 3;
const char *fmt;
va_start(va, dflt);
if (!dflt) sev = va_arg(va, int);
fmt = va_arg(va, const char *);
fprintf(stderr, "[%d] ", sev);
vfprintf(stderr, fmt, va);
fprintf(stderr, "\n");
va_end(va);
return 0;
}
int main()
{
PRINT(1, "Incompatible types %s and %s", "Apple", "Orange");
PRINT("Microphone test: %d, %d, %d, ...", 1, 2, 3);
return 0;
}
This solution is dangerous, because the msg function is only safe if it is generated by the macro. And the macro is only safe if the format string is a string literal beginning with a double quote. The macro expands the arguments by one boolean argument to the left and hides the argument incompatibility in a variadic argument list.
It may be a nice trick, but you'll be better off having separate, clearly named macros.
C macros do not have the ability to inspect their arguments. As noted in the answer you posted, there is a sneaky way to do different things based on the number of arguments, but that's the extent of it. If you already have a variable number of arguments outside of the overload you are trying to do, it will not be possible. If all you need is a default level:
#define PRINTNORM(...) PRINT(3, __VA_ARGS__)
or whatever you'd like to call it. IMHO, cleaner code than overloading PRINT.
Simply use another value for your need. And perhaps a bit of magic with variadic macro would help.
something like:
#define PRINT( print_level , print_string , ... )\
switch( print_level ) \
/* as many syslog cas as needed */
case( 5 ):\
case( 4 ):\
case( 3 ):\
case( 2 ):\
case( 2 ):\
case( 1 ):\
syslog( print_level , __VA_ARGS__ );\
break ; \
default: \
case( 0 ): \
printf( __VA_ARGS__ ); \ /* else we simply want to print it */
break ;
Edit:
Doc on variadic macro: https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
P99 has conditional macro evaluation. Here you could probably use something like P99_IF_EMPTY for something like
#define PRINT(LEV, ...) my_print(P99_IF_EMPTY(LEV)(3)(LEV), __VA_ARGS__)
this would still have you insert a , for the case of the empty argument but comes probably close to what you want to achieve.
Optional arguments coming before other mandatory arguments can potentially be handled by folding them together in parentheses:
PRINT((2, "%d%d\n"), i, j);
PRINT("%d%d\n", i, j);
Define PRINT like this:
#define PRINT(SL, ...) PRINT_LEVEL(APPLY(CAT(LEVEL, IS_SPLIT(SL)), IDENTITY SL), APPLY(CAT(FSTRING, IS_SPLIT(SL)), IDENTITY SL), __VA_ARGS__)
#define PRINT_LEVEL(LEVEL, ...) syslog(LEVEL, __VA_ARGS__)
PRINT detects whether the first argument is an atom (just the format string) or a parenthesized list of two elements (printlevel + string), and expands into the real implementation PRINT_LEVEL accordingly, either extracting the level from the first argument, or supplying a default value.
Definitions for IS_SPLIT and the other helpers are as follows:
#define LEVEL_0(_S) 3
#define LEVEL_1(L, S) L
#define FSTRING_0(S) K_##S
#define FSTRING_1(L, S) S
#define CAT(A, B) CAT_(A, B)
#define CAT_(A, B) A ## B
#define APPLY(F, ...) F(__VA_ARGS__)
#define IDENTITY(...) __VA_ARGS__
#define K_IDENTITY
#define IS_SPLIT(...) IS_SPLIT_1(IDENTITY __VA_ARGS__)
#define IS_SPLIT_1(...) IS_SPLIT_2(__VA_ARGS__, _1, _0, _)
#define IS_SPLIT_2(_X, _Y, R, ...) R
I know you can return a character string from a normal function in C as in this code
#include <stdio.h>
char* returnstring(char *pointer) {
pointer="dog";
return pointer;
}
int main(void)
{
char *dog = NULL;
printf("%s\n", returnstring(dog));
}
However, I can't find a way to be able to return character strings in #define functions, as in this code
#include <stdio.h>
#define returnstring(pointer) { \
pointer="dog"; \
return pointer; \
}
int main(void)
{
char *dog = NULL;
printf("%s\n", returnstring(dog));
}
I know that there are workarounds(like using the first program). I just want to know if it is possible
Thinking about a "#define function" is, IMO, the wrong way to approach this.
#define is a blunt instrument which amounts to a text find/replace. It knows little to nothing about C++ as a language, and the replace is done before any of your real code is even looked at.
What you have written isn't a function in its own right, it is a piece of text that looks like one, and it put in where you have written the alias.
If you want to #define what you just did, that's fine (I didn't check your example specifically, but in general, using #define for a function call and substituting the arguments is possible), but think twice before doing so unless you have an amazing reason. And then think again until you decide not to do it.
You can't "return" from a macro. Your best (ugh... arguably the "best", but anyway) bet is to formulate your macro in such a way that it evaluates to the expression you want to be the result. For example:
#define returnstring(ptr) ((ptr) = "hello world")
const char *p;
printf("%s\n", returnstring(p));
If you have multiple expression statements, you can separate them using the horrible comma operator:
#define even_more_dangerous(ptr) (foo(), bar(), (ptr) = "hello world")
If you are using GCC or a compatible compiler, you can also take advantage of a GNU extension called "statement expressions" so as to embed whole (non-expression) statements into your macro:
#define this_should_be_a_function(ptr) ({ \
if (foo) { \
bar(); \
} else { \
for (int i = 0; i < baz(); i++) { \
quirk(); \
} \
} \
ptr[0]; // last statement must be an expression statement \
})
But if you get to this point, you could really just write a proper function as well.
You don't return anything from a #defined macro. Roughly speaking, the C preprocessor replaces the macro call with the text of the macro body, with arguments textually substituted into their positions. If you want a macro to assign a pointer to "dog" and evaluate to the pointer, you can do this:
#define dogpointer(p) ((p)="dog")
The thing is returnstring as a macro does not do what it says; it also assigns the value to the parameter. The function does as it says, even if it (somewhat oddly) uses its parameter as a temporary variable.
The function is equivalent to:
char* returnstring(char *ignored) {
return "dog";
}
The function macro is much the same as:
#define returnstring(pointer) pointer = "dog"
Which begs the question, why not call it assign_string?
Or why not just have:
#define dogString "dog"
And write:
int main(void)
{
char *dog = NULL;
printf("%s\n", dog = dogString);
}
The function for assignString is:
char* assignstring(char **target{
*target= "dog";
return *target;
}
You can then have a macro:
assign_string_macro(pointer) assignstring(&pointer)
Ultimately if you want to "return character strings in #define functions", then all you need is:
#define returnstring(ignored) "dog"
What does ## do in C?
Example:
typedef struct
{
unsigned int bit0:1;
unsigned int bit1:1;
unsigned int bit2:1;
unsigned int bit3:1;
unsigned int bit4:1;
unsigned int bit5:1;
unsigned int bit6:1;
unsigned int bit7:1;
} _io_reg;
#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bit##bt
(I know what it all does besides the ## part.)
It is string concatenation, as part of the preprocessor macro.
(In this context, "string" refers to a preprocessor token of course, or a "string of source code", and not a C-string.)
It's called the pasting operator; it concatenates the text in bt with the text bit. So for example, if your macro invocation was
REGISTER_BIT(x, 4)
It would expand to
((volatile _io_reg*)&x)->bit4
Without it, you couldn't put a macro argument directly beside text in the macro body, because then the text would touch the argument name and become part of the same token, and it'd become a different name.
The operator ## concatenates two arguments leaving no blank spaces between them:
#define glue(a,b) a ## b
glue(c,out) << "test";
That is the token pasting operator.
That's part of the macro definition.
It allows you to concatenate strings inside the macro.
In your case, you can use bt from 7 to 0 like this:
REGISTER_BIT(myreg, 0)
and it will be expanded as:
((volatile _io_reg*)&myreg)->bit0
Without this, you'd have to define the bit part of the macro as one of the macro's arguments:
#define REGISTER_BIT(rg,bt) ((volatile _io_reg*)&rg)->bt
where the usage would be:
REGISTER_BIT(myreg, bit0)
which is more cumbersome.
This also allows you to build new names.
Assume you have these macros:
#define AAA_POS 1
#define AAA_MASK (1 << AAA_POS)
#define BBB_POS 2
#define BBB_MASK (1 << BBB_POS)
and you want a macro that extracts AAA from a bit vector. You can write it like this:
#define EXTRACT(bv, field) ((bv & field##_MASK) >> field##_POS)
and then you use it like this:
EXTRACT(my_bitvector, AAA)
It's not a C construct, it's a preprocessor feature. In this case it's meant to evaluate the bt variable and concatenate it with the bit prefix. Without the hashes you would have bitbt there, which obviously would not work.
Here's an example from ffmpeg, a macro that registers both audio and video filters:
#define REGISTER_FILTER(X, x, y) \
{ \
extern AVFilter ff_##y##_##x; \
if (CONFIG_##X##_FILTER) \
avfilter_register(&ff_##y##_##x); \
}
and usage can be:
REGISTER_FILTER(AECHO,aecho,af);
REGISTER_FILTER(VFLIP,vflip,vf);