Type-checking casts in (GNU) C

This is word to let the world know that I have found a way to make the C++ new-style casts, specifically static_cast<> and const_cast<>, in (GNU) C (that's right, not C++).

I had seen annotation-only “casts” in C projects (and not just my own) before. Just grepping -Pin '\w+_cast\(' in all .tar.gz/.tar.bz2 source tarballs that are contained within a bunch of .src.rpms ([gklmnop]*.src.rpm from OpenSUSE was my run) of the distro already reveal quite a bit. It looks like this:

/* The below macro is intended to be used for type casts. By using this
macro, type casts can be easily located in the source code with
tools like "grep". */
#define JAS_CAST(t, e) ((t) (e))

/* C++ style type casts */
#define const_cast(m_type, m_expr) ((m_type) (m_expr))

(These two examples from libjasper and Midnight Commander (mc))

Essentially, these developers just use the plain old cast, and it does not do much except the annotation. In fact, it can easily lead to warnings not appear, because it is essentially just the old reinterpreting cast. That is to say:

/* Former code */
static void foo(const char *y)
{
    char *x = const_cast(char *, y);
}

This can easily fall apart when forgetting to change half of the code (which is bound to happen at some point in larger codebases):

/* Former code */
static void foo(const int *y)
{
    char *x = const_cast(char *, y);
}

You do not get any warning for the apparent type mismatch. While that sucks, it is justified, because you actually used what is a reinterpret_cast, not an actual const_cast with a #define like that above. Comes along GNU C.

The presence of the ARRAY_SIZE/BUILD_BUG_ON macros in the Linux kernel source inspired me to try something similarly freaky with GCC's extensions, for fun and profit.

The result are some macros that actually do type-checking instead of an annotation that has a reinterpret-pitfall in it. I am not aware of this macro setup having been done before, as it is pretty impossible to grep or google for such without turning up lots of C++ code. It is further my assumption that since the GNU C compiler itself only carries annotating “CONST_CAST” macros, that my approach is indeed novel.

The reference implementation for the discovered macros is present in libHX starting from 2.0. Linux distro packages will be doing an update soon. Interested parties are encouraged to use of libHX/defs.h.

Using these new macros, const_cast1(char *, y); (note the '1' in “const_cast1”) will not allow y to be something other than char * or const char *!

Keywords: signed_cast const_cast static_cast reinterpret_cast GNU C

Posted 2008-12-24 11:12 / Tags: Compilers. / link