Some people (myself included) dislike the syntax of the C++ const_cast<> operator, because;
- It seems misnamed, because it removes const.
- It seems to violate DRY, because it requires a redundant type arg.  
But I am wrong: it is not misnamed, since it can also add const and/or volatile "cv" qualifiers, and it only partially violates DRY, since the compiler will catch any errors. So I dislike it slightly less and use it: it is safer than the C-style cast.
Using gcc's typeof, you can have almost the same type safety in C.
The following C code sample gives a CONST_CAST(T, x) macro, and illustrates its use:
#define REMOVE_QUALIFIER(cv, T, x) /* this macro evaluates its args only once */   \
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), cv T), ((T)(x)), \
    (void)0)
#define ADD_QUALIFIER(cv, T, x) /* this macro evaluates its args only once */      \
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(x), T), ((cv T)(x)), \
    (void)0)
#ifdef __GNUC__
#define CONST_CAST(T, x)  REMOVE_QUALIFIER(const, T, x) // "misnamed"
#else
#define CONST_CAST(T, x)  ((T)(x)) // fallback to standard C cast
#endif
void foo(void);
void foo(void) {
    const int *a   = 0;
    const float *x = 0;
    int *b        = a;                          // warning
    int *c        = (int *)a;                   // no warning, unsafe standard cast
    int *d        = (int *)x;                   // no warning, and likely wrong
    int *e        = CONST_CAST(int *, a);       // ok
    int *f        = CONST_CAST(int *, x);       // error
    unsigned *g   = CONST_CAST(unsigned *, a);  // error
    const int **h = &b;                         // warning
    const int **i = ADD_QUALIFIER(const, int **, &b); // ok
    const int **j = ADD_QUALIFIER(const, int **, &x); // error
}
This technique can also be used to change the signedness of a type, reminiscent of C++'s std::make_signed and std::make_unsigned, or Boost traits. For example:
#define MAKE_UNSIGNED(T, x)  ADD_QUALIFIER(unsigned, T, x) // T usually char*