Silly _Generic trick: const_cast(T, exp)

J

Joel C. Salomon

Untested, but I think this should work:

#ifdef __cplusplus
#define const_cast(T, exp) const_cast<T>(exp)
#else
#define const_cast(T, exp) _Generic((exp), const T : (T)(exp))
#endif

void foo(void) {
const int i = 42;

// &i is compatible with `const int *` = `int const *`
int *pi = const_cast(int *, &i);

// pi is compatible with `const int const *` = `int const *`
int const *pci = const_cast(int const *, pi);

// fails: types incompatible
double *pd = const_cast(double *, &i);
} /* d--n google groups*/

Disgusting, no? ;)

(Even if this works, it won't be too hard to make it break. Typedef'd pointers will do it: `const vptr` = `void * const` != `void const *`.)

I've got another yucky hack brewing: a reinterpret_cast that casts everything *except* qualifiers.

--Joel
 
J

Jens Thoms Toerring

Joel C. Salomon said:
Untested, but I think this should work:
#ifdef __cplusplus
#define const_cast(T, exp) const_cast<T>(exp)
#else
#define const_cast(T, exp) _Generic((exp), const T : (T)(exp))
#endif

What's '_Generic' meant to do? Without knowing that there's no
way to figure out what this is meant to do (or what you expect
it to do).
I've got another yucky hack brewing: a reinterpret_cast that casts
everything *except* qualifiers.

I 'm not yet convinced that dragging C++ stuff into C will
work (or will be beneficial). A bit more of context of what
you intent to get from that might be useful...

Regards, Jens
 
B

Ben Pfaff

Joel C. Salomon said:
Untested, but I think this should work:

#ifdef __cplusplus
#define const_cast(T, exp) const_cast<T>(exp)
#else
#define const_cast(T, exp) _Generic((exp), const T : (T)(exp))
#endif

I use:

/* Expands to a void expression that checks that POINTER is an
expression whose type is a qualified or unqualified version of
a type compatible with TYPE (a pointer type) and, if not,
causes a compiler warning to be issued (on typical compilers).

Examples:

int *ip;
const int *cip;
const int **cipp;
int ***ippp;
double *dp;

// None of these causes a warning:
CHECK_POINTER_HAS_TYPE (ip, int *);
CHECK_POINTER_HAS_TYPE (ip, const int *);
CHECK_POINTER_HAS_TYPE (cip, int *);
CHECK_POINTER_HAS_TYPE (cip, const int *);
CHECK_POINTER_HAS_TYPE (dp, double *);
CHECK_POINTER_HAS_TYPE (dp, const double *);
CHECK_POINTER_HAS_TYPE (cipp, const int **);
CHECK_POINTER_HAS_TYPE (cipp, const int *const *);
CHECK_POINTER_HAS_TYPE (ippp, int ***);
CHECK_POINTER_HAS_TYPE (ippp, int **const *);

// None of these causes a warning either, although it is unusual to
// const-qualify a pointer like this (it's like declaring a "const int",
// for example).
CHECK_POINTER_HAS_TYPE (ip, int *const);
CHECK_POINTER_HAS_TYPE (ip, const int *const);
CHECK_POINTER_HAS_TYPE (cip, int *const);
CHECK_POINTER_HAS_TYPE (cip, const int *const);
CHECK_POINTER_HAS_TYPE (cipp, const int **const);
CHECK_POINTER_HAS_TYPE (cipp, const int *const *const);
CHECK_POINTER_HAS_TYPE (ippp, int ***const);
CHECK_POINTER_HAS_TYPE (ippp, int **const *const);

// Provokes a warning because "int" is not compatible with "double":
CHECK_POINTER_HAS_TYPE (dp, int *);

// Provoke warnings because C's type compatibility rules only allow
// adding a "const" qualifier to the outermost pointer:
CHECK_POINTER_HAS_TYPE (ippp, const int ***);
CHECK_POINTER_HAS_TYPE (ippp, int *const**);
*/
#define CHECK_POINTER_HAS_TYPE(POINTER, TYPE) \
((void) sizeof ((TYPE) (POINTER) == (POINTER)))

/* Given expressions A and B, both of which have pointer type,
expands to a void expression that causes a compiler warning if
A and B are not pointers to qualified or unqualified versions
of compatible types.

Examples similar to those given for CHECK_POINTER_HAS_TYPE,
above, can easily be devised. */
#define CHECK_POINTER_COMPATIBILITY(A, B) ((void) sizeof ((A) == (B)))

/* Equivalent to casting POINTER to TYPE, but also issues a
warning if the cast changes anything other than an outermost
"const" or "volatile" qualifier. */
#define CONST_CAST(TYPE, POINTER) \
(CHECK_POINTER_HAS_TYPE (POINTER, TYPE), \
(TYPE) (POINTER))
 
J

Joel C. Salomon

What's '_Generic' meant to do? Without knowing that there's no
way to figure out what this is meant to do (or what you expect
it to do).

If `exp` is type-compatible with `const T` -- i.e., `exp` is itself of
type `T` or `const T` -- then cast it to type T. Otherwise the (C1x)
compiler will complain of incompatible types.

As the `#ifdef __cplusplus` documents, this is *intended* to be a
work-alike clone of C++'s `const_cast said:
I'm not yet convinced that dragging C++ stuff into C will
work (or will be beneficial). A bit more of context of what
you intent to get from that might be useful...

Oh, I don't know that it's a *good* idea; I was just opening up the
discussion. Given all the arguments that C++ puts forward for its
`*_cast<>` -- findable with grep, control over exactly what is being
cast away, etc. -- and assuming that C1x gives us the tools to do
something similar, what say we come up with a prototype and discuss it?

--Joel
 
I

Ian Collins

If `exp` is type-compatible with `const T` -- i.e., `exp` is itself of
type `T` or `const T` -- then cast it to type T. Otherwise the (C1x)
compiler will complain of incompatible types.

So where do we get hold of a C1x compiler?
 
I

Ian Collins

What's '_Generic' meant to do? Without knowing that there's no
way to figure out what this is meant to do (or what you expect
it to do).


I 'm not yet convinced that dragging C++ stuff into C will
work (or will be beneficial). A bit more of context of what
you intent to get from that might be useful...

They would be useful for one of the main reasons they are useful in C++:
you can grep for them! An awful lot of casts in C code are necessary
and they can mask errors. An easy way to spot them is a big help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top