C11 _Generic evaluating another macro - c

I'd like to make _Generic evaluate another macro. In the example below, db_put_u8 will insert a uint8_t into the buffer and while at it, it will also leave a log message. The log helps me understand if I missed a field. Hence the macro. I have reduced the functionality to illustrate the problem here, but in practice it's supposed to have for various data types.
#include <stdio.h>
#include <stdint.h>
#define db_put_u8(con, name, val) \
do { \
fputs(name "<- " #val, con); \
} while(0)
#define db_put(con, name, val) _Generic(val, uint8_t: db_put_u8)(con, name, val)
int main(void)
{
uint8_t v = 10;
db_put(stdout, "some-field", v);
return 0;
}
When I try compiling this, I get an error:
test.c:15:5: error: use of undeclared identifier 'db_put_u8'
db_put(stdout, "some-field", v);
^
test.c:9:55: note: expanded from macro 'db_put'
#define db_put(con, name, val) _Generic(val, uint8_t: db_put_u8)(con, name, val)
^
1 error generated.
Am I doing _Generic right? The generic selection syntax does not explicitly restrict calling macros in it. Can someone explain what I am doing wrong and how to fix it?

This line:
#define db_put(con, name, val) _Generic(val, uint8_t: db_put_u8)(con, name, val)
First of all has to change to:
#define db_put(con, name, val) _Generic(val, uint8_t: db_put_u8(con, name, val))
Because _Generic works at compile time, not preprocessor time. And after preprocessing, db_put_u8 will not expand because it doesn't exist as a macro. db_put_u8(arg1, arg2, arg3), however, does, so you have to put the brackets in the generic. However, there's another error then: _Generic expects an eression, so a do while loop would not work. In this case though, you don't even need to encase your macro in a loop because it's just one statement, so it's free from the potential issues of macros with many statements. Your final program should look something like this:
#include <stdio.h>
#include <stdint.h>
#define db_put_u8(con, name, val) \
fputs(name "<- " #val, con)
#define db_put(con, name, val) _Generic(val, uint8_t: db_put_u8(con, name, val))
int main(void)
{
uint8_t v = 10;
db_put(stdout, "some-field", v);
return 0;
}
EDIT: In response to the comment, there is a solution. So long as the second thing to do in db_put_u8 is also a statement, you could use the comma operator and a few more brackets. Here's an example program to put it to the test:
#include <stdio.h>
#include <stdint.h>
#define db_put_u8(con, name, val) \
(fputs(name "<- " #val, con), \
fputs("\nAnother test line\n", con))
#define db_put(con, name, val) \
(_Generic(val, uint8_t: db_put_u8(con, name, val)))
int main(void)
{
uint8_t v = 10;
db_put(stdout, "some-field", v);
return 0;
}
When I run this, it outputs:
some-field<- v
Another test line

Macro db_put_u8 would expand as do ... while(...) statement which is not an expression. _Generic expects expression thus error is observed. You should provide a function named db_put_u8. The function name decays to pointer to the function which is an an expression.
Other way around is to replace db_put_u8 with 'fputs(name "<- " #val, con)' inside _Generic and remove final '(name, val,con)'
#define db_put(con, name, val) \
_Generic(val, uint8_t: fputs(name "<- " #val, con))
If db_put_u8 cannot be changed then one could use an C extension named statement expression. It is supported by GCC and CLANG. Basically it allows to put arbitrary statement info ({ ... }). The last expression evaluated is returned as result.
#define db_put(con, name, val) \
_Generic(val, uint8_t: ({db_put_u8(con, name, val);}))

Related

Function overloading in C with _Generic when __VA_ARG__ can be empty

I am looking to use the _Generic preprocessor directive to achieve function overloading. I learned to use it from this wonderfully detailed answer.
However, it doesn't seem to cover this case:
#include <stdio.h>
void foo_one(int);
void foo_two(int, float*);
#define FIRST_VARG(_A, ...) _A
#define foo(_X, ...) _Generic( (FIRST_VARG(__VA_ARGS__,)), \
float* : foo_two, \
default : foo_one) (_X, __VA_ARGS__)
void foo_one(int A)
{
printf("FOO ONE: %d\n", A);
}
void foo_two(int A, float* B)
{
printf("FOO TWO: %d, %f", A, *B);
}
void main()
{
float x = 3.14;
float* y = &x;
foo(1); // This statement pops an error
foo(2, y);
}
Here, you can see that the first argument to both functions is an integer. However, the second argument of the second function is a float*. Visual Studio complains about the calling foo(1), but not when calling foo(2, y). The error is
error C2059: syntax error: ')'
I know Visual Studio can support _Generic with a small trick. So, I feel like there is something I am doing wrong. There is a comment in the answer where I learned about _Generic that suggests using (SECOND(0, ##__VA_ARGS__, 0), etc. But I don't understand it.
Can someone walk me through how I could achieve my intended result?
There are two issues. First is selecting the second argument of foo for generic selection in the case when there is no second argument.
Other is #define foo(_X, ...) which will not work for foo(1) because the function macro expect two or more arguments. It often works but it a compiler specific extensions. Compiling in pedantic mode will raise a warning. See https://godbolt.org/z/z7czvGvbc
A related issue is expanding to (_X, __VA_ARGS__)which will not work for foo(1) where ... maps to nothing.
The both issues can be addressed with placing a dummy type (NoArg) at the end of the list prior to extracting the second argument. It will both extend the list and add a value that can be used by _Generic to correctly dispatch the function expression.
#include <stdio.h>
void foo_one(int);
void foo_two(int, float*);
typedef struct { int _; } NoArg;
// use compound literal to form a dummy value for _Generic, only its type matters
#define NO_ARG ((const NoArg){0})
#define foo_(args, a, b, ...) \
_Generic((b) \
,NoArg: foo_one \
,default: foo_two \
) args
// pass copy of args as the first argument
// add NO_ARG value, only its type matters
// add dummy `~` argument to ensure that `...` in `foo_` catches something
#define foo(...) foo_((__VA_ARGS__), __VA_ARGS__, NO_ARG, ~)
void foo_one(int A)
{
printf("FOO ONE: %d\n", A);
}
void foo_two(int A, float* B)
{
printf("FOO TWO: %d, %f\n", A, B ? *B : 42.0f);
}
#define TEST 123
int main(void)
{
float x = 3.14;
float* y = &x;
foo(1); // This statement pops an error
foo(2, y);
foo(TEST, NULL);
return 0;
}
The last issue is addressed by passing a tuple with original arguments as extra argument to foo_ macro, this argument is later passed to the call operator of expression selected by _Generic.
This solution works with all major C17 compilers (gcc, clang, icc, msvc).

Combing _Generic with other macros

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");
}

C variable type assert

uint32_t fail_count = 0;
...
if(is_failed)
if(fail_count < UINT32_MAX - 1 )
++fail_count;
It works fine, but this code is fragile. Tomorrow, I may change the type of fail_count from uint32_t to int32_t and I forget to update UINT32_MAX.
Is there any way to assert fail_count is a uint32_t at the function where I have written my ifs?
P.S. 1- I know it is easy in C++ but I'm looking for a C way.
P.S. 2- I prefer to use two asserts than relying on the compiler warnings. Checking the number size via sizeof should work but is there any way to distinguish if type is unsigned?
As of C11, you can use a generic selection macro to produce a result based on the type of an expression. You can use the result in a static assertion:
#define IS_UINT32(N) _Generic((N), \
uint32_t: 1, \
default: 0 \
)
int main(void) {
uint32_t fail_count = 0;
_Static_assert(IS_UINT32(fail_count), "wrong type for fail_count");
}
You could of course use the result in a regular assert(), but _Static_assert will fail at compile time.
A better approach could be dispatching the comparison based on type, again using generic selection:
#include <limits.h>
#include <stdint.h>
#define UNDER_LIMIT(N) ((N) < _Generic((N), \
int32_t: INT32_MAX, \
uint32_t: UINT32_MAX \
) -1)
int main(void) {
int32_t fail_count = 0;
if (UNDER_LIMIT(fail_count)) {
++fail_count;
}
}
As you mentioned GCC, you can use a compiler extension to accomplish this in case you are not using C11:
First write a macro that emulates the C++ is_same. And then call it with the types you want to compare.
A minimal example for your particular case:
#include<assert.h>
#define is_same(a, b) \
static_assert(__builtin_types_compatible_p(typeof(a), typeof(b)), #a " is not unsigned int")
int main()
{
int fail_count = 0;
is_same(fail_count, unsigned int);
}
The compiler asserts:
<source>: In function 'main':
<source>:4:3: error: static assertion failed: "fail_count is not unsigned int"
static_assert(__builtin_types_compatible_p(typeof(a), typeof(b)), #a " is not unsigned int")
^~~~~~~~~~~~~
<source>:9:5: note: in expansion of macro 'is_same'
is_same(fail_count, unsigned int);
^~~~~~~
See Demo
What about a low-tech solution that works even with K&R C and any compiler past and present?
Place the right comment in the right place:
/*
* If this type is changed, don't forget to change the macro in
* if (fail_count < UINT32_MAX - 1) below (or file foobar.c)
*/
uint32_t fail_count = 0;
With a proper encapsulation this should refer to exactly one place in the code.
Don't tell me you increment the fail count in many places. And if you do, what
about a
#define FAIL_COUNT_MAX UINT32_MAX
right next to the declaration? That's more proper and clean code anyway.
No need for all the assertion magic and rocket sciencery :-)

variable name as macro argument

I am trying to create a macro in c, that will take a variable name, and declare it. I could call it like this:
MY_MACRO(test);
Would produce:
int test;
In order to achieve this I went this way:
#define MY_MACRO(var) /
int ##var; /
But the compiler doesn't understand this. Does such syntax exist in C11?
I wouldn't recommend doing such a thing. Anyway, there are two problems. First of all, to skip a newline, you need \, not /.
Second, the ## is wrong. What it does is concatenating the var to the int. So with MY_MACRO(foo) you would get intfoo;, but you want int foo;
The macro needs to be like this:
#define MY_MACRO(var) \
int var
## is not applicable here as it concatenates the token with something else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MY_MACRO(var) int var
or
#define MY_MACRO(var) \
int var \
void foo(void)
{
MY_MACRO(a);
a = rand();
printf("%d\n",a);
}
## pastes two tokens together into one token.
#define poem(var)\
int jack##var;
// Produces 'int jacksprat;'
poem(sprat)
In your case you don't need to do anything special at all, you can just use the argument directly:
#define MY_MACRO(var)\
int var;
The correct syntax would be something along the lines of this:
#define MY_MACRO(ident) \
int ident
int main() {
MY_MACRO(test);
test =42;
return test;
}
However, have you been looking into typedefs? Unlike typedefs, macros are considered bad practice.

Expanding a macro to a different default macro if an argument is missing

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

Resources