Re: _Generic.3: EXAMPLES: C++'s static_cast() in C

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 11/11/22 18:08, Alejandro Colomar wrote:>>>> Dear readers,

I've been developing a cast macro for C that is similar to C++'s static_cast(), which allows to:

- Cast between a limited set of types (actually, pointers to those types).
- Can add const, but not remove it.
- Easily grep for all casts.

But forbids:

- Cast between unrelated types.
- Removing const.

This improves type safety in C, where casts allow programmers to commit all kinds of crimes by disabling most compiler warnings.

The macro I originally wrote, allows to convert between u_char and char, for a code base that uses u_char internally but has to interface libc and syscalls. That one is unnecessary for most code bases which just use char (and that's how it should be for strings; if you want unsigned 'char's, you should use '-funsigned-char').

But there are cases where the kernel or libc forces us to use casts, like for example in bind(2).  That's for what the following macro is, and I plan to add it to the EXAMPLES section in _Generic(3), replacing the previous program.

The macro itself is quite huge, which might discourage some, but it is not so complex.  I'll release it to the public domain.  Could you please review it?

Cheers,

Alex


With C2x's typeof_unqual(), it can be made a bit smaller, and better (it now supports volatile).


And since it makes no sense to convert between some of the derivative types (e.g., sa_in to sa_un), it can be further simplified:

v4:

- Reintroduce some typeof_unqual() that were accidentally removed in v3.
- Align casts for readability.


v5:

- Casting to sockaddr_storage is useless.  Only casting from it makes sense.

I'll send shortly after an v6, if I manage to simplify after this change, but I'll post this v5 to not have a sudden jump with an unreadably interdiff.

#define sockaddr_cast(t, p)                            \
    _Generic(&*(p),                                    \
    struct sockaddr *:                                 \
        _Generic((typeof_unqual(t)) NULL,              \
        struct sockaddr_in *:             (t) (p),     \
        struct sockaddr_in6 *:            (t) (p),     \
        struct sockaddr_un *:             (t) (p),     \
        default: (p)),                                 \
    struct sockaddr **:                                \
        _Generic((typeof_unqual(t)) NULL,              \
        struct sockaddr_in **:            (t) (p),     \
        struct sockaddr_in6 **:           (t) (p),     \
        struct sockaddr_un **:            (t) (p),     \
        default: (p)),                                 \
    const struct sockaddr *:                           \
        _Generic((t) NULL,                             \
        const struct sockaddr_in *:       (t) (p),     \
        const struct sockaddr_in6 *:      (t) (p),     \
        const struct sockaddr_un *:       (t) (p),     \
        default: (p)),                                 \
                                                       \
    struct sockaddr_in *:                              \
        _Generic((typeof_unqual(t)) NULL,              \
        struct sockaddr *:                (t) (p),     \
        default: (p)),                                 \
    struct sockaddr_in **:                             \
        _Generic((typeof_unqual(t)) NULL,              \
        struct sockaddr **:               (t) (p),     \
        default: (p)),                                 \
    const struct sockaddr_in *:                        \
        _Generic((t) NULL,                             \
        const struct sockaddr *:          (t) (p),     \
        default: (p)),                                 \
                                                       \
    struct sockaddr_in6 *:                             \
        _Generic((typeof_unqual(t)) NULL,              \
        struct sockaddr *:                (t) (p),     \
        default: (p)),                                 \
    struct sockaddr_in6 **:                            \
        _Generic((typeof_unqual(t)) NULL,              \
        struct sockaddr **:               (t) (p),     \
        default: (p)),                                 \
    const struct sockaddr_in6 *:                       \
        _Generic((t) NULL,                             \
        const struct sockaddr *:          (t) (p),     \
        default: (p)),                                 \
                                                       \
    struct sockaddr_un *:                              \
        _Generic((typeof_unqual(t)) NULL,              \
        struct sockaddr *:                (t) (p),     \
        default: (p)),                                 \
    struct sockaddr_un **:                             \
        _Generic((typeof_unqual(t)) NULL,              \
        struct sockaddr **:               (t) (p),     \
        default: (p)),                                 \
    const struct sockaddr_un *:                        \
        _Generic((t) NULL,                             \
        const struct sockaddr *:          (t) (p),     \
        default: (p)),                                 \
                                                       \
    struct sockaddr_storage *:                         \
        _Generic((typeof_unqual(t)) NULL,              \
        struct sockaddr *:                (t) (p),     \
        struct sockaddr_in *:             (t) (p),     \
        struct sockaddr_in6 *:            (t) (p),     \
        struct sockaddr_un *:             (t) (p),     \
        default: (p)),                                 \
    struct sockaddr_storage **:                        \
        _Generic((typeof_unqual(t)) NULL,              \
        struct sockaddr **:               (t) (p),     \
        struct sockaddr_in **:            (t) (p),     \
        struct sockaddr_in6 **:           (t) (p),     \
        struct sockaddr_un **:            (t) (p),     \
        default: (p)),                                 \
    const struct sockaddr_storage *:                   \
        _Generic((t) NULL,                             \
        const struct sockaddr *:          (t) (p),     \
        const struct sockaddr_in *:       (t) (p),     \
        const struct sockaddr_in6 *:      (t) (p),     \
        const struct sockaddr_un *:       (t) (p),     \
        default: (p)),                                 \
                                                       \
    default:                                           \
        (p)                                            \
    )


--
<http://www.alejandro-colomar.es/>

Attachment: OpenPGP_signature
Description: OpenPGP digital signature


[Index of Archives]     [Kernel Documentation]     [Netdev]     [Linux Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux