I need to use _Generic in C, to be able to return specialized values according to the variable type.
const char *encode_char_ptr(char *x)
{
return (x ? x : "NULL");
}
....
#define encode(x) _Generic((x), \
char *: encode_char_ptr, \
const char *: encode_const_char_ptr, \
bool: encode_bool, \
default: return_param)(x)
so that for various types there's a specialized handling that returns some string, but for the rest (default), the argument itself will be returned. What could be a possible implementation for "return_param"? or do i have to implement a specialized function for each possible type?
You can call the functions within the generic selection branches, and then the default branch can simply evaluate to the value of the argument. The only complication is that all branches must be semantically valid. So we can do a trick here for scalar types: make another generic selection. If it is of proper type then return the argument as is, otherwise return 0 cast to that type, producing 0 for arithmetic types, or null pointer for pointer types. The branch would not be evaluated so it is safe. Therefore we get
#define coerce_scalar(type, arg) _Generic((arg), type: (arg), default: (type)0)
#define encode(x) _Generic((x), \
char *: encode_char_ptr(coerce_scalar(char *, (x))), \
const char *: encode_const_char_ptr(coerce_scalar(const char *, (x))), \
bool: encode_bool(coerce_scalar(bool, (x))), \
default: (x))
This is possible to expand to structure, union types too by using a compound literal for the other branch initialized with {0} - though mostly I guess it would be pointers to structs, i.e. scalars again.
But the real solution would be to not call encode at all for other types.
Related
It looks like the typeof operator is likely to be accepted into the next C standard, and I was looking to see if there was a way to leverage this to create a macro using portable ISO-C that can get the length of an array passed into it or fail to compile if a pointer is passed into it. Normally generic selection can be used to force a compiler error when using an unwanted type by leaving it out of the generic association list, but in this case, we need a default association to deal with arrays of any length, so instead I am trying to force a compiler error for the generic association for the type we don't want. Here's an example of what the macro could look like:
#define ARRAY_SIZE(X) _Generic(&(X), \
typeof(&X[0]) *: sizeof(struct{_Static_assert(0, "Trying to get the array length of a pointer"); int _a;}), \
default: (sizeof(X) / sizeof(X[0])) \
)
The problem is that _Static_assert is tripping even when the generic association selected is the default association. For sake of simplicity, since the issue at hand is not related anything being introduced in C23, we'll make a test program that works explicitly to reject a pointer to int:
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE(X) _Generic(&(X), \
int **: sizeof(struct{_Static_assert(0, "Trying to get the array length of a pointer"); int _a;}), \
default: (sizeof(X) / sizeof(X[0])) \
)
int main(void) {
int x[100] = {0};
int *y = x;
int (*z)[100] = {&x};
printf("length of x: %zu\n", ARRAY_SIZE(x));
printf("length of y: %zu\n", ARRAY_SIZE(y));
printf("length of z: %zu\n", ARRAY_SIZE(z));
printf("length of *z: %zu\n", ARRAY_SIZE(*z));
return EXIT_SUCCESS;
}
Building the above with -std=c11, I find _Static_assert tripping on all expansions of ARRAY_SIZE when I would expect to only have problems with the pointers that will use the int ** generic association.
According to 6.5.1.1 p3 of the C11 standard for Generic Selection,
None of the expressions from any other generic association of the generic selection is evaluated
Is this a bug in gcc and clang, or is there something I've missed in the standard that would cause the compile-time evaluation of this _Static_assert in the unused generic association?
It doesn't matter which generic selection is evaluated.
When the expression that is part of a _Status_assert has the value 0, this is considered a constraint violation and the compiler is required to generate a diagnostic.
You can't really mix _Static_assert with expressions that should return a value, such as a function-like macro. You could perhaps work around that with a "poor man's static assert", like one of the ugly tricks we used before C11:
#define POOR_STATIC_ASSERT(expr) (int[expr]){0}
#define CHECK(X) _Generic((&X), \
int **: 0,\
default: (sizeof(X) / sizeof(X[0])) \
)
#define ARRAY_SIZE(X) ( (void)POOR_STATIC_ASSERT(CHECK(X)), CHECK(X) )
Here the comma operator is called to have the macro CHECK return the size or zero, in case a type is valid or not. Then call the same macro again to have that one returned from the function-like macro ARRAY_SIZE. This will lead to some cryptic error from an ISO C compiler such as "error: ISO C forbids zero-size array".
The next problem is that &(X) in _Generic is by no means guaranteed to boil down to a int** so this macro isn't safe or reliable. Regarding array sizes though, there's a trick we can use. A pointer to an array of no size (incomplete type) is compatible with every array of the same element type no matter it's size. The macro could be rewritten as:
#define POOR_STATIC_ASSERT(expr) (int[expr]){0}
#define CHECK(X) _Generic((&X), \
int (*)[]: sizeof(X) / sizeof(X[0]), \
default: 0)
#define ARRAY_SIZE(X) ( (void)POOR_STATIC_ASSERT(CHECK(X)), CHECK(X) )
This will work for any int array no matter size but fail for everything else.
Utilizing some of the suggestions from Lundin's answer, I have come up with the following solution to the simplified problem:
#define STATIC_ASSERT_EXPRESSION(X, ERROR_MESSAGE) (sizeof(struct {_Static_assert((X), ERROR_MESSAGE); int _a;}))
#define NO_POINTERS(X) _Generic(&(X), \
int (*)[]: 1, \
default: 0 \
)
#define ARRAY_SIZE(X) ( (void)STATIC_ASSERT_EXPRESSION(NO_POINTERS(X), "Cannot retrieve the number of array elements from a pointer"), (sizeof(X) / sizeof(X[0])) )
For the actual use-case to be type generic using typeof, which should be coming to the C23 standard, replace the NO_POINTERS macro using this:
#define NO_POINTERS(X) _Generic(&(X), \
typeof(*X) (*)[]: 1, \
default: 0 \
)
By moving the _Static_assert outside of the Generic Selection, it will only be evaluated with the value that actually returns from the selection, so it won't get fired off for existing in an unused selection. Additionally, the number of elements calculation was also removed from the generic selection so that expression of the generic selection could safely be used in a Static Assert even if your array was a Variable-Length array which requires its size to be calculated at run-time.
The Static Assert itself is placed inside of an anonymous struct that we take the sizeof so that it is a part of an expression. And then as in Lundin's example, we use the comma operator to have that expression evaluated, and then thrown out and use the results of the array size calculation.
With this, we reject pointers while getting the number of elements in both static arrays and VLAs, plus we get a nice compiler error message when trying to pass in a pointer.
I use the GCC compiler (version 9.2.0)
I want to use the typeof function in C but it raises an error (error: expected expression before 'typeof')
If you need more info, just ask me .
int a = 5;
double b;
//the expected result is "0", but it raises an error instead...
printf("%d", typeof(a) == typeof(b));
You can get the behavior you want by dropping gcc extensions and using standard C _Generic:
#define my_typeof(x) _Generic((x), int: 1, double: 2)
printf("%d", my_typeof(a) == my_typeof(b));
The only catch is that you have to type out support for every type manually.
GCC has a built-in function called __builtin_types_compatible_p that takes two arguments that are types (not expressions) and returns the int value 1 if the types are compatible, or 0 if they are incompatible.
OP's example could be written as:
int a = 5;
double b;
printf("%d", __builtin_types_compatible_p(typeof(a), typeof(b)));
From the online documentation:
Built-in Function: int __builtin_types_compatible_p (type1, type2)
You can use the built-in function __builtin_types_compatible_p to determine whether two types are the same.
This built-in function returns 1 if the unqualified versions of the types type1 and type2 (which are types, not expressions) are compatible, 0 otherwise. The result of this built-in function can be used in integer constant expressions.
This built-in function ignores top level qualifiers (e.g., const, volatile). For example, int is equivalent to const int.
The type int[] and int[5] are compatible. On the other hand, int and char * are not compatible, even if the size of their types, on the particular architecture are the same. Also, the amount of pointer indirection is taken into account when determining similarity. Consequently, short * is not similar to short **. Furthermore, two types that are typedefed are considered compatible if their underlying types are compatible.
An enum type is not considered to be compatible with another enum type even if both are compatible with the same integer type; this is what the C standard specifies. For example, enum {foo, bar} is not similar to enum {hot, dog}.
You typically use this function in code whose execution varies depending on the arguments’ types. For example:
#define foo(x) \
({ \
typeof (x) tmp = (x); \
if (__builtin_types_compatible_p (typeof (x), long double)) \
tmp = foo_long_double (tmp); \
else if (__builtin_types_compatible_p (typeof (x), double)) \
tmp = foo_double (tmp); \
else if (__builtin_types_compatible_p (typeof (x), float)) \
tmp = foo_float (tmp); \
else \
abort (); \
tmp; \
})
Note: This construct is only available for C.
I understand what one would use C11's 'Generic' for, and I would like to use it within a static assertion to guarantee that two user-defined types (typedefs) are the same primative type.
I have made a macro that maps each primative type to an enumerated value, and verified that it works as desired. However, when I try to compare the equality of two resultant macros from two types in a static assert, I get a compiler error. When you comment out the static assert, the code works as expected.
It almost seems as if the static assert is being evaluated by the compiler BEFORE the generic expansion is evaluated. Could this be the case? And where can I go to verify the behavior of this?
Example Code:
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
typedef enum
{
UTIL_TYPE_ENUM_BOOL,
UTIL_TYPE_ENUM_CHAR,
UTIL_TYPE_ENUM_SCHAR,
UTIL_TYPE_ENUM_UCHAR,
UTIL_TYPE_ENUM_SHORT,
UTIL_TYPE_ENUM_USHORT,
UTIL_TYPE_ENUM_INT,
UTIL_TYPE_ENUM_UINT,
UTIL_TYPE_ENUM_LONG,
UTIL_TYPE_ENUM_ULONG,
UTIL_TYPE_ENUM_LONG_LONG,
UTIL_TYPE_ENUM_ULONG_LONG,
UTIL_TYPE_ENUM_FLOAT,
UTIL_TYPE_ENUM_DOUBLE,
UTIL_TYPE_ENUM_LONG_DOUBLE,
UTIL_TYPE_ENUM_OTHER,
} UtilTypeEnum_t;
// returns the enumerated value representing a primitive type
#define UTIL_TYPE_GET_TYPE_ENUM(x) _Generic((x), \
_Bool: UTIL_TYPE_ENUM_BOOL, \
char: UTIL_TYPE_ENUM_CHAR, \
signed char: UTIL_TYPE_ENUM_SCHAR, \
unsigned char: UTIL_TYPE_ENUM_UCHAR, \
short int: UTIL_TYPE_ENUM_SHORT, \
unsigned short int: UTIL_TYPE_ENUM_USHORT, \
int: UTIL_TYPE_ENUM_INT, \
unsigned int: UTIL_TYPE_ENUM_UINT, \
long int: UTIL_TYPE_ENUM_LONG, \
unsigned long int: UTIL_TYPE_ENUM_ULONG, \
long long int: UTIL_TYPE_ENUM_LONG_LONG, \
unsigned long long int: UTIL_TYPE_ENUM_ULONG_LONG, \
float: UTIL_TYPE_ENUM_FLOAT, \
double: UTIL_TYPE_ENUM_DOUBLE, \
long double: UTIL_TYPE_ENUM_LONG_DOUBLE, \
default: UTIL_TYPE_ENUM_OTHER)
typedef int32_t foo_t;
typedef float bar_t;
// IF YOU COMMENT OUT THE STATIC ASSERT, THE CODE WILL COMPILE AND WORKS AS EXPECTED
_Static_assert((UTIL_TYPE_GET_TYPE_ENUM(foo_t)==UTIL_TYPE_GET_TYPE_ENUM(bar_t)),"ERROR");
int main(void)
{
foo_t foo;
bar_t bar;
printf("foo's type = %d\n", UTIL_TYPE_GET_TYPE_ENUM(foo));
printf("bar's type = %d\n", UTIL_TYPE_GET_TYPE_ENUM(bar));
if (UTIL_TYPE_GET_TYPE_ENUM(foo) != UTIL_TYPE_GET_TYPE_ENUM(bar))
{
printf("Not the same type!\n");
}
else
{
printf("Same type!\n");
}
return 0;
}
#endif
Compiler Error:
$ gcc foo.c
foo.c:35:49: error: expected expression before ‘,’ token
#define UTIL_TYPE_GET_TYPE_ENUM(x) _Generic((x), \
^
foo.c:77:17: note: in expansion of macro ‘UTIL_TYPE_GET_TYPE_ENUM’
_Static_assert((UTIL_TYPE_GET_TYPE_ENUM(foo_t)==UTIL_TYPE_GET_TYPE_ENUM(bar_t)),"ERROR");
^~~~~~~~~~~~~~~~~~~~~~~
foo.c:35:49: error: expected expression before ‘,’ token
#define UTIL_TYPE_GET_TYPE_ENUM(x) (_Generic((x), \
^
foo.c:77:49: note: in expansion of macro ‘UTIL_TYPE_GET_TYPE_ENUM’
_Static_assert((UTIL_TYPE_GET_TYPE_ENUM(foo_t)==UTIL_TYPE_GET_TYPE_ENUM(bar_t)),"ERROR");
^~~~~~~~~~~~~~~~~~~~~~~
foo.c:77:16: error: expression in static assertion is not an integer
_Static_assert((UTIL_TYPE_GET_TYPE_ENUM(foo_t)==UTIL_TYPE_GET_TYPE_ENUM(bar_t)),"ERROR");
The argument to a _Generic selection must be a valid C expression, the type of which is then examined. You provide a type name, which simply isn't an expression.
To get an expression of the types you are after, you can use a compound literal:
_Static_assert((UTIL_TYPE_GET_TYPE_ENUM((foo_t){0})==UTIL_TYPE_GET_TYPE_ENUM((bar_t){0})),"ERROR");
(foo_t){0} and (bar_t){0} are now expressions of the types you want to compare, and so may be used in the generic selection.
You can achieve what you want, or at least something close, with
#define SAME_TYPE(t1,t2) _Generic((t1){0}, t2: 1, default: 0)
_Static_assert(SAME_TYPE(foo_t, bar_t));
This does not involve enumerations that assume a finite set of types (not supporting struct types, etc.) and does not depend on the "GNU C" typeof extension (which is not part of the C language).
This works for types, not expressions. It can easily be extended to the case where one argument is a type and the other is an expression. If you need to assert that two expressions have the same type, that's at least somewhat harder to do purely in C, and might not be possible. If you're in the special case where they're variables, the expression
1 ? &var1 : &var2
is a constraint violation if var1 and var2 have different types, but sadly GCC treats this as a warning by default rather than an error. I'm not aware of a way to make it into an error without a full -Werror because it doesn't seem to be in its own warning group, just the anonymous on-by-default warnings...
As already noted in another answer, you cannot pass a type as the first argument to _Generic. You need to provide an expression, and the compiler will deduce if the type of the expression matches against the list.
It is possible to simplify your code. You do not need to use those enumerations. gcc supports the typeof extension, which allows you to do something like:
#define EXPR_HAVE_SAME_TYPE(E1, E2) \
_Generic((E1), typeof(E2): 1, default: 0)
_Static_assert(EXPR_HAVE_SAME_TYPE(foo, foo), "...");
_Static_assert(!EXPR_HAVE_SAME_TYPE(foo, bar), "...");
You can use this for types if you create expressions:
#define SAME_TYPE(T1, T2) \
EXPR_HAVE_SAME_TYPE(*(T1 *)0, *(T2 *)0)
_Static_assert(SAME_TYPE(foo_t, foo_t), "...");
_Static_assert(!SAME_TYPE(foo_t, bar_t), "...");
A similar notion was mentioned in R.'s comment and answer.
While looking at Linux kernel's implementation of doubly linked circular lists, I've found following macro:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
The way this works is that it returns pointer to structure given only address of one of its members:
struct blabla
{
int value;
struct list_head *list;
}
Thus you can get pointer to blabla (and get to "value") given only pointer to list.
To my question, how would I make this as portable as possible (best case conforming to C89/C99?). Due to usage of typeof(), this is gcc only.
This is what I've got so far:
#define container_of(ptr, type, member) ( \
(type *) (char *)(ptr)-offsetof(type,member)\
)
Is this snippet conforming to ISO standards (and thus should be able to be compiled on any conforming compiler)?
As Ouah commented, the ({ ... }) statement expression is a GNU extension; you won't be able to use that. Your core expression is close to what's required, but doesn't have enough parentheses:
#define container_of(ptr, type, member) \
((type *) ((char *)(ptr) - offsetof(type, member)))
That looks clean to me. It's only spread across two lines for SO.
The macro is written the way it is to perfom a type check on ptr. It's possible to use a compound literal instead of the statement expression and fall back to a simple check for pointers instead of using __typeof__ if the compiler is not gcc-compatible:
#ifdef __GNUC__
#define member_type(type, member) __typeof__ (((type *)0)->member)
#else
#define member_type(type, member) const void
#endif
#define container_of(ptr, type, member) ((type *)( \
(char *)(member_type(type, member) *){ ptr } - offsetof(type, member)))
ISO C90 compatible version with type check. (However, caveat: two evaluations of ptr!)
#define container_of(ptr, type, member) \
((type *) ((char *) (ptr) - offsetof(type, member) + \
(&((type *) 0)->member == (ptr)) * 0))
struct container {
int dummy;
int memb;
};
#include <stddef.h>
#include <stdio.h>
int main()
{
struct container c;
int *p = &c.memb;
double *q = (double *) p;
struct container *pc = container_of(p, struct container, memb);
struct container *qc = container_of(q, struct container, memb);
return 0;
}
Test:
$ gcc -Wall containerof.c
containerof.c: In function ‘main’:
containerof.c:20:26: warning: comparison of distinct pointer types lacks a cast
containerof.c:20:21: warning: unused variable ‘qc’
containerof.c:19:21: warning: unused variable ‘pc’
We get the distinct pointer types warning for 26, but not 25. That is our diagnostic about pointers being misused.
I first tried placing the type check into the left hand side of a comma operator, gcc complains about that having no effect, which is a nuisance. But by making it an operand, we ensure that it is used.
The &((type *) 0)->member trick isn't well defined by ISO C, but it's widely used for defining offsetof. If your compiler uses this null pointer trick for offsetof, it will almost certainly behave itself in your own macro.
Yes, you can make "container_of" macros to be strictly ISO C conforming. To do this you need two things:
take rid of GNU exensions;
find a way to check types compatibility.
Basically, types checking is not run time operation, but compile time rather. And I not see any reasons, why original "container_of" implementation creates new variable just to assign it and perform type checking. This can be done without creation of new variable in some expression which is only computed (and types checked) in compile time. Fortunately, we have no much options in C and only choice is to use "sizeof(expression)" to check the type. See an example:
#define container_of(ptr, type, member) \
( (void)sizeof(0 ? (ptr) : &((type *)0)->member), \
(type *)((char*)(ptr) - offsetof(type, member)) )
In first line types compatibility is checked (for ternary operator compiler must insure, that types might be converted to common type, or that both types are compatible). Second line is the same, as in original "container_of" macros.
You can play with test program on GodBolt (https://godbolt.org/z/MncvzWfYn) and make sure, that this ISO conforming variant works even in Microsoft's Visual Studio compiler.
PS: After some time, I found that the following variant can be better:
#define CONTAINER_OF(ptr, type, member) \
( (void)sizeof(0 ? (ptr) : &((type*)0)->member), \
(typeof(_Generic((typeof(ptr))0, const typeof(*(typeof(ptr))0)*: (const type*)0, default: (type*)0))) \
((uintptr_t)(const void*)(ptr) - offsetof(type, member)) )
The difference, is that it preserves const qualifier from ptr and assigns it to the result, for example:
if ptr argument is const struct * pointer, the result then will have a type of const type *, despite if the type is const or not;
if ptr argument is non-const pointer (struct*), the result then will have type type*, which may be const or non-const, depending on the type of type argument.
As a result, preserving const qualifier reduces the possibility of the errors, when const pointer to some structure translated into non-const pointer via container_of macro.
Unfortunately, this version requires C23 or non-standard typeof() operator for earlier versions of C standard.
Another reason for ISO-compiant container_of macro, as opposed to implementation from Linux kernel, is that latter uses "statement expression" GCC-extension which works badly in a case, when argument ptr is a temporary variable. The latter might happen, when container_of macro is applied to the result of a function invocation (container_of(func().x, struct y, m), here is assumed, that func() returns a structure in which x is an array of structures), or to the compound statement (container_of((&(struct S){...}), struct B, m)). In both of these cases, a call to container_of macro borrowed from linux will result in a dangling pointer! This happens because a temporary object passed as ptr argument will be destroyed after the first semicolon (at the first line of Linux implementation of container_of macro), and because a variable created by a compound statement expression will be destroyed at the end of the nearest block, which is "statement expression" itself. ISO-compliant implementation of container_of macro have no such issues.
Using c11 _Generic is there a way to map multiple types to a single value?
eg:
_Generic(e, \
A *: foo_expression, \
B **: foo_expression, \
C: foo_expression, \
enum D: bar_expression, \
void *: bar_expression)
Is there a way to group types? (this isn't valid syntax just to express the intent)
_Generic(e, \
A *: B **: C: foo_expression, \
enum D: void *: bar_expression)
The reason I ask is args foo and baz can end up being large expressions (which can't necessarily be refactored into functions), so a way to avoid a lot of duplication would be good.
Note:
If there is no supported way using _Generic, I _could_ make a varargs macro to glue multiple args to a single value...
#define GENERIC_TYPE_GLUE3(answer, arg0, arg1) \
arg0: answer, arg1: answer
#define GENERIC_TYPE_GLUE4(answer, arg0, arg1, arg2) \
arg0: answer, arg1: answer, arg2: answer
....
... have many of these macros, then use a varargs wrapper to automatically use the right one, see: https://stackoverflow.com/a/24837037/432509
_Generic(e, \
GENERIC_TYPE_GLUE(foo_expression, short int, long),
GENERIC_TYPE_GLUE(bar_expression, float, double))
(See working example: https://gist.github.com/ideasman42/4426f255880ff6a53080)
No, similar to switch there is no syntax foreseen to regroup multiple cases for _Generic. Your regrouping macro approach is probably the correct one for your purpose, then. You may have a look into macro meta programming as is done by boost or my package P99 that allow you to have just one such macro that also does the counting of the cases for.
For your use case you can use the type promotion rules
_Generic((e)+0ULL, \
unsigned long long: foo, \
default: bar)
If you have other cases than floating point, you may even go one step further
_Generic((e)+0ULL, \
unsigned long long: foo, \
default: _Generic((e)+0.0L,\
long double: bar, \
default: blur))
This supposes that all your expressions e have arithmetic type. Remaining for the default in would then be _Complex types and all pointer types.
For the kind of usage you have in mind you should do such promotions, anyhow, because compilers currently interpret the controlling expression of _Generic differently. Some would also consider an object of type double const differently from double, for example. So this would really give you a lot of cases to consider, if you'd have to differentiate all possible type qualifications.