Combing _Generic with other macros - c

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

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).

Is it possible to implement GNU C's typeof(x) with C11's _Generic?

To make some code compile in C and C++ I use this in a few places:
#ifdef __cplusplus
#define typeof(x) decltype(x) // works ok in most cases, except C++ reference types
#endif
char* a = (typeof(a)) malloc(4);
In C, this compiles to char* a = (char *) malloc(4) where the cast is totally unecessary, but in C++ void * is not implicitly promoted to char * and an error is issued if a cast is not present.
This is just as well when I can compile with -std=gnu11 on GCC or Clang, but what when I want to make my code compile as ISO C11? I thought I could use C11's _Generic to implement typeof(x) to cast some types:
#define gettype(x) _Generic((x), \
short: (short ), \
char: (char ), \
char*: (char *), \
default: (void *) )
int main (void) {
short a = (gettype(a)) 1;
return a;
}
But no matter what type defined in gettype(x) is given in a's declaration,
typeof.h: In function ‘main’:
typeof.h:2:24: error: expected expression before ‘,’ token
short: (short ), \
^
typeof.h:8:13: note: in expansion of macro ‘gettype’
char a = (gettype(a)) 1;
^~~~~~~
typeof.h:8:25: error: expected ‘,’ or ‘;’ before numeric constant
char a = (gettype(a)) 1;
gcc -E says that line expands just fine:
short a = (_Generic((a), short: (short ), char: (char ), char*: (char *), default: (void *) )) 1; ^
Is there some syntax I am missing, or is it simply not possible in C to generate cast code using _Generic?
The problem is that you can't have a partial expression inside the generic selection. A possible work-around could be to put a full expression inside it:
#define cast(from, to) _Generic((from), \
short: (short) (to), \
char: (char) (to), \
char*: (char*) (to), \
default: (void*) (to))
int main (void) {
short a = cast(a, 1);
return 0;
}
No, it's not possible. (Now watch someone prove me wrong!)
In a _Generic expression, each generic-association is either
type-name : assignment-expression
or
default : assignment-expression
It can't be a type name or something that expands to a type name. In particular, though a _Generic expression is resolved at compile time, it is not a macro. The final result is always an expression.
And I don't believe there's any other way to do what you want in standard C.
I just figured out..if Visual C++, in C, not C++, if you have two unrelated non-void pointer result types in a ternary expression, the type of the ternary expression is the first.
This can be useful.
So, in a corner I am painted into where I have a bunch of C code, I need to cast a void* to the type of something else, within a macro, that should not double evaluate...
typedef struct DesiredType { ... } DesiredType;
typedef struct ArbitraryType { ... } ArbitraryType;
ArbitraryType/*void*/* function_to_void_double_eval (void* a)
{
...
}
#if defined(_MSC_VER) && !defined(__cplusplus)
#define MACRO(x) (0 ? (DesiredType*)0 : function_to_avoid_double_eval(x))
#else // assume gcc
use typeof and temporaries in a macro
#endif

Use of pasting operator `##` with types in C

Is it possible to define a macro for the C preprocessor which takes an array as argument and expands to <type of array elements>_string? For example if x in an array of integers the macro invoked with argument x should expand to int_string.
I tried with
#define TypePaste(array) typeof(array[0])##_string
but it expands to )_string.
Even using multiple levels of indirection for the ## operand the macro doesn't expand correctly.
That's not possible. At the translation phase (the preprocessing phase) where macros are expanded and tokens are concatenated, the compiler (at this point, the preprocessor) does not yet have the notion of a type and thus cannot possibly generate types.
It is not all that clear what problem you are trying to solve, but given your comment:
the macro should expand to the name of an existing function. I'd like to define a function <type>_string for every existing type and then use the macro to select the right function according to the type of the array given.
Then you could use the C11 _Generic keyword:
#include <stdio.h>
void int_string (size_t size, int array[size])
{
printf("I am %s, do stuff here.\n", __func__);
}
void float_string (size_t size, float array[size])
{
printf("I am %s, do stuff here.\n", __func__);
}
#define TypePaste(array) \
_Generic( array, \
int: int_string, \
float: float_string ) \
(sizeof(array)/sizeof(*array), array) // function parameters
int main()
{
int i_arr[5];
float f_arr[3];
TypePaste(i_arr);
TypePaste(f_arr);
}
Output:
I am int_string, do stuff here.
I am float_string, do stuff here.
Note: this assumes that the passed parameter is a local/file scope allocated array. If passing a pointer, there's no type safety and the program will fail.
C11's _Generic type selection is the "proper" way to do what you want. There are other, platform dependent solutions, tough.
If you are using gcc – you don't say so eplicitly, but you use gcc's extension typeof already – you can use gcc's statement expresions and nested functions to create a comparison function for qsort on the spot:
double a[5] = {8.4, 8.1, 9.3, 12.2, 5.2};
qsort(a, 5, sizeof(*a), ({
int cmp(const void *p, const void *q) {
const typeof(a[0]) *pp = p;
const typeof(a[0]) *qq = q;
return (*pp < *qq) ? -1 : (*pp > *qq);
}
cmp;
}));
This creates a function and returns its address. (The last statement of a compound expression is its value. The scope of the local variables is the statement expression, but a nested function is not created on the stack so its safe to return a pointer to that function.)
For primitive types, where you want to sort according to the comparison operators < and >, you can turn that into a macro:
#define COMPARE(ARRAY)({ \
int cmp(const void *p, const void *q) { \
const typeof(ARRAY[0]) *pp = p; \
const typeof(ARRAY[0]) *qq = q; \
return (*pp < *qq) ? -1 : (*pp > *qq); \
} \
cmp; \
})
qsort(a, 5, sizeof(*a), COMPARE(a));
or even:
#define SORT(ARRAY, N) \
qsort(ARRAY, N, sizeof(*ARRAY), COMPARE(ARRAY))
SORT(a, 5);
That's not Standard C, so if you need compatibility between platforms, this is out of the question.

Returning a Character String from #define Function

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"

Typechecking macro arguments in C

Is it possible to typecheck arguments to a #define macro? For example:
typedef enum
{
REG16_A,
REG16_B,
REG16_C
}REG16;
#define read_16(reg16) read_register_16u(reg16); \
assert(typeof(reg16)==typeof(REG16));
The above code doesn't seem to work. What am I doing wrong?
BTW, I am using gcc, and I can guarantee that I will always be using gcc in this project. The code does not need to be portable.
gcc supports typeof
e.g. a typesafe min macro taken from the linux kernel
#define min(x,y) ({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \
(void) (&_x == &_y); \
_x < _y ? _x : _y; })
but it doesn't allow you to compare two types. Note though the pointer comparison which Will generate a warning - you can do a typecheck like this (also from the linux kernel)
#define typecheck(type,x) \
({ type __dummy; \
typeof(x) __dummy2; \
(void)(&__dummy == &__dummy2); \
1; \
})
Presumably you could do something similar - i.e. compare pointers to the arguments.
The typechecking in C is a bit loose for integer-related types; but you can trick the compiler by using the fact that most pointer types are incompatible.
So
#define CHECK_TYPE(var,type) { __typeof(var) *__tmp; __tmp = (type *)NULL; }
This will give a warning, "assignment from incompatible pointer type" if the types aren't the same. For example
typedef enum { A1,B1,C1 } my_enum_t;
int main (int argc, char *argv) {
my_enum_t x;
int y;
CHECK_TYPE(x,my_enum_t); // passes silently
CHECK_TYPE(y,my_enum_t); // assignment from incompatible pointer type
}
I'm sure that there's some way to get a compiler error for this.
This is an old question, But I believe I have a general answer that according to Compiler Explorer apears to work on MSVC, gcc and clang.
#define CHECK_TYPE(type,var) { typedef void (*type_t)(type); type_t tmp = (type_t)0; if(0) tmp(var);}
In each case the compiler generates a useful error message if the type is incompatible. This is because it imposes the same type checking rules used for function parameters.
It can even be used multiple times within the same scope without issue. This part surprises me somewhat. (I thought I would have to utilize "__LINE__" to get this behavior)
Below is the complete test I ran, commented out lines all generate errors.
#include <stdio.h>
#define CHECK_TYPE(type,var) { typedef void (*type_t)(type); type_t tmp = (type_t)0; if(0) tmp(var);}
typedef struct test_struct
{
char data;
} test_t;
typedef struct test2_struct
{
char data;
} test2_t;
typedef enum states
{
STATE0,
STATE1
} states_t;
int main(int argc, char ** argv)
{
test_t * var = NULL;
int i;
states_t s;
float f;
CHECK_TYPE(void *, var); //will pass for any pointer type
CHECK_TYPE(test_t *, var);
//CHECK_TYPE(int, var);
//CHECK_TYPE(int *, var);
//CHECK_TYPE(test2_t, var);
//CHECK_TYPE(test2_t *, var);
//CHECK_TYPE(states_t, var);
CHECK_TYPE(int, i);
//CHECK_TYPE(void *, i);
CHECK_TYPE(int, s); //int can be implicitly used instead of enum
//CHECK_TYPE(void *, s);
CHECK_TYPE(float, s); //MSVC warning only, gcc and clang allow promotion
//CHECK_TYPE(float *, s);
CHECK_TYPE(float, f);
//CHECK_TYPE(states_t, f);
printf("hello world\r\n");
}
In each case the compiler with -O1 and above did remove all traces of the macro in the resulting code.
With -O0 MSVC left the call to the function at zero in place, but it was rapped in an unconditional jump which means this shouldn't be a concern. gcc and clang with -O0 both remove everything except for the stack initialization of the tmp variable to zero.
No, macros can't provide you any typechecking. But, after all, why macro? You can write a static inline function which (probably) will be inlined by the compiler - and here you will have type checking.
static inline void read_16(REG16 reg16) {
read_register_16u(reg16);
}
Building upon Zachary Vander Klippe's answer, we might even go a step further (in a portable way, even though that wasn't a requirement) and additionally make sure that the size of the passed-in type matches the size of the passed-in variable using the "negative array length" trick that was commonly used for implementing static assertions in C (prior to C11, of course, which does provide the new _Static_assert keyword).
As an added benefit, let's throw in some const compatibility.
#define CHECK_TYPE(type,var) \
do {\
typedef void (*type_t) (const type);\
type_t tmp = (type_t)(NULL);\
typedef char sizes[((sizeof (type) == sizeof (var)) * 2) - 1];\
if (0) {\
const sizes tmp2;\
(void) tmp2;\
tmp (var);\
}\
} while (0)
Referencing the new typedef as a variable named tmp2 (and, additionally, referencing this variable, too) is just a method to make sure that we don't generate more warnings than necessary, c.f., -Wunused-local-typedefs and the like. We could have used __attribute__ ((unused)) instead, but that is non-portable.
This will work around the integer promotion "issue" in the original example.
Example in the same spirit, failing statements are commented out:
#include <stdio.h>
#include <stdlib.h>
#define CHECK_TYPE(type,var) \
do {\
typedef void (*type_t) (const type);\
type_t tmp = (type_t)(NULL);\
typedef char sizes[((sizeof (type) == sizeof (var)) * 2) - 1];\
if (0) {\
const sizes tmp2;\
(void) tmp2;\
tmp (var);\
}\
} while (0)
int main (int argc, char **argv) {
long long int ll;
char c;
//CHECK_TYPE(char, ll);
//CHECK_TYPE(long long int, c);
printf("hello world\n");
return EXIT_SUCCESS);
}
Naturally, even that approach isn't able to catch all issues. For instance, checking signedness is difficult and often relies on tricks assuming that a specific complement variant (e.g., two's complement) is being used, so cannot be done generically. Even less so if the type can be a structure.
To continue the idea of ulidtko, take an inline function and have it return something:
inline
bool isREG16(REG16 x) {
return true;
}
With such as thing you can do compile time assertions:
typedef char testit[sizeof(isREG16(yourVariable))];
No. Macros in C are inherently type-unsafe and trying to check for types in C is fraught with problems.
First, macros are expanded by textual substitution in a phase of compilation where no type information is available. For that reason, it is utterly impossible for the compiler to check the type of the arguments when it does macro expansion.
Secondly, when you try to perform the check in the expanded code, like the assert in the question, your check is deferred to runtime and will also trigger on seemingly harmless constructs like
a = read_16(REG16_A);
because the enumerators (REG16_A, REG16_B and REG16_C) are of type int and not of type REG16.
If you want type safety, your best bet is to use a function. If your compiler supports it, you can declare the function inline, so the compiler knows you want to avoid the function-call overhead wherever possible.

Resources