Silly _Generic trick: const_cast(T, exp)

Discussion in 'C Programming' started by Joel C. Salomon, May 20, 2011.

  1. 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
     
    Joel C. Salomon, May 20, 2011
    #1
    1. Advertising

  2. Joel C. Salomon <> wrote:
    > 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
    --
    \ Jens Thoms Toerring ___
    \__________________________ http://toerring.de
     
    Jens Thoms Toerring, May 20, 2011
    #2
    1. Advertising

  3. Joel C. Salomon

    Ben Pfaff Guest

    "Joel C. Salomon" <> writes:

    > 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))

    --
    Ben Pfaff
    http://benpfaff.org
     
    Ben Pfaff, May 20, 2011
    #3
  4. On 05/20/2011 06:48 PM, Jens Thoms Toerring wrote:
    > Joel C. Salomon <> wrote:
    >> 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).


    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<>`.

    >> 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...


    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
     
    Joel C. Salomon, May 21, 2011
    #4
  5. Joel C. Salomon

    Ian Collins Guest

    On 05/21/11 11:29 AM, Joel C. Salomon wrote:
    > On 05/20/2011 06:48 PM, Jens Thoms Toerring wrote:
    >> Joel C. Salomon<> wrote:
    >>> 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).

    >
    > 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?

    --
    Ian Collins
     
    Ian Collins, May 21, 2011
    #5
  6. (Jens Thoms Toerring) writes:
    > Joel C. Salomon <> wrote:
    >> 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).


    It's a new feature in the upcoming C201X standard.

    See <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1547.pdf>, section
    6.5.1.1. (I'm not sure whether that's the latest and/or best C201X
    draft.)

    [...]

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, May 21, 2011
    #6
  7. Joel C. Salomon

    Ian Collins Guest

    On 05/21/11 10:48 AM, Jens Thoms Toerring wrote:
    > Joel C. Salomon<> wrote:
    >> 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...


    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.

    --
    Ian Collins
     
    Ian Collins, May 21, 2011
    #7
  8. Ian Collins <> writes:
    > On 05/21/11 11:29 AM, Joel C. Salomon wrote:
    >> On 05/20/2011 06:48 PM, Jens Thoms Toerring wrote:
    >>> Joel C. Salomon<> wrote:
    >>>> 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).

    >>
    >> 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'm sure they'll become available as quickly as C99 compilers did.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, May 21, 2011
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Kaspar Minosiants

    [help] const_cast

    Kaspar Minosiants, Jul 21, 2003, in forum: C++
    Replies:
    2
    Views:
    427
    John Harrison
    Jul 21, 2003
  2. Joel C. Salomon

    Nested _Generic selections

    Joel C. Salomon, Jan 13, 2012, in forum: C Programming
    Replies:
    9
    Views:
    458
    Shao Miller
    Jan 17, 2012
  3. Jens Gustedt

    Re: Thoughts on the _Generic feature?

    Jens Gustedt, Oct 6, 2012, in forum: C Programming
    Replies:
    0
    Views:
    338
    Jens Gustedt
    Oct 6, 2012
  4. Prathamesh Kulkarni
    Replies:
    8
    Views:
    182
    Keith Thompson
    Dec 10, 2013
  5. David Librik

    Does C11's _Generic further complicate parsing?

    David Librik, May 25, 2014, in forum: C Programming
    Replies:
    1
    Views:
    63
    Ben Bacarisse
    May 25, 2014
Loading...

Share This Page