Hi,
I have been wondering whether it makes sense to add a small utility trying to make typecasts in C as type-safe as possible.
The problem is that typecasts are sometimes unavoidable. For an example, let's take a look at the following snippet using Gnulib's xlist module:
struct foo
{
int bar;
};
gl_list_t list = gl_list_create_empty (GL_ARRAY_LIST, NULL, NULL, NULL, false);
struct foo foo = { .bar = 1 };
gl_list_add_last (list, &foo);
gl_list_iterator_t i = gl_list_iterator (list);
struct foo *elt;
while (gl_list_iterator_next (&i, (const void **) &elt, NULL))
++elt->bar;
gl_list_iterator_free (&i);
Here, the typecast '(const void **)' is needed as 'gl_list_iterator_next' expects an argument of that type and because 'struct foo **elt' is not implicitly convertible to 'const void **' (in fact, even not to 'void **').
The problem with this typecast is that the compiler wouldn't have complained if I had forgotten to write the address operator '&' before 'elt'.
So what I have in mind are macros that do a type conversion from A to B and that signal an error on modern compilers if the input is not of type A. For this, the C11 construct _Generic can be used.
The macros could look like
CAST (<from-type>, <to-type>, <expr>)
CVR_CAST (<type>, expr) /* removes cvr qualifier */
ADDRESS_CAST (<from-type>, <to-type>, expr)
expanding, respectively, into
_Generic ((<expr>), (<from-type>): ((<to-type>) (<expr>)))
_Generic ((<expr>), (<type>): ((<type>) (<expr>)),
(const <type>): ((<type> (<expr>)),
(const volatile <type>): ((<type>) (<expr>)),
...)
_Generic ((<expr>), (<from-type>): (((<to-type>) *) &(<expr>)))
The names and the exact semantics and number of macros are, of course, debatable.
Marc