[PATCH v7] _Generic.3: EXAMPLES: Add sockaddr_cast() macro

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

 



This macro is an example of how C++-style casts can be implemented in C.
They are better than C's casts because they only allow certain
conversions, while disallowing most.  This adds considerable type
safety.  They also make code more greppable.

A macro similar to const_cast() can also be implemented in a similar
manner:

 /* This code is in the public domain. */

 #define qual_cast(t, p)                               \
    _Generic(typeof_unqual(&*(p)),                     \
    typeof_unqual(t):                                  \
        _Generic(&*(p),                                \
        const t:          (t) (p),                     \
        volatile t:       (t) (p),                     \
        const volatile t: (t) (p),                     \
        default:              (p))                     \
    default:                                           \
        (p)                                            \
    )

Note that typeof_unqual() is yet unsupported by GCC and Clang, and will
be added to C23.  Similar behavior can be achieved by combining GNU
builtins.

Cc: Andrew Clayton <andrew@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Alejandro Colomar <alx@xxxxxxxxxx>
---

v7:

- Casting from sockaddr_storage is useless.  It violates aliasing rules,
  since something declared that type cannot be accessed (it doesn't have
  useful members) except aliased to u_char.  So, the type is only useful
  as argument to sizeof() and in unions.

- Fix the call to getsockname(2) to use a sockaddr_un instead, to avoid
  violating aliasing rules.

 man3/_Generic.3 | 91 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 90 insertions(+), 1 deletion(-)

diff --git a/man3/_Generic.3 b/man3/_Generic.3
index ddee5f6c4..6ff5e24ea 100644
--- a/man3/_Generic.3
+++ b/man3/_Generic.3
@@ -27,12 +27,101 @@ .SH DESCRIPTION
 .SH STANDARDS
 C11 and later.
 .SH EXAMPLES
+The following code demonstrates how to write
+a macro similar to C++'s
+.BR \%static_cast (),
+which will allow casting safely between a limited set of types.
+It is useful for example when calling
+system calls or library functions that use compatible structures,
+like for example
+.BR bind (2)
+with
+.BR \%sockaddr (3type).
+.IP
+.EX
+/* This code is in the public domain. */
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#define sockaddr_cast(t, p)                            \e
+    _Generic(&*(p),                                    \e
+    struct sockaddr *:                                 \e
+        _Generic((typeof_unqual(t)) NULL,              \e
+        struct sockaddr_in *:             (t) (p),     \e
+        struct sockaddr_in6 *:            (t) (p),     \e
+        struct sockaddr_un *:             (t) (p),     \e
+        default:                              (p)),    \e
+    struct sockaddr **:                                \e
+        _Generic((typeof_unqual(t)) NULL,              \e
+        struct sockaddr_in **:            (t) (p),     \e
+        struct sockaddr_in6 **:           (t) (p),     \e
+        struct sockaddr_un **:            (t) (p),     \e
+        default:                              (p)),    \e
+    const struct sockaddr *:                           \e
+        _Generic((t) NULL,                             \e
+        const struct sockaddr_in *:       (t) (p),     \e
+        const struct sockaddr_in6 *:      (t) (p),     \e
+        const struct sockaddr_un *:       (t) (p),     \e
+        default:                              (p)),    \e
+                                                       \e
+    struct sockaddr_in *:                              \e
+        _Generic((typeof_unqual(t)) NULL,              \e
+        struct sockaddr *:                (t) (p),     \e
+        default:                              (p)),    \e
+    struct sockaddr_in **:                             \e
+        _Generic((typeof_unqual(t)) NULL,              \e
+        struct sockaddr **:               (t) (p),     \e
+        default:                              (p)),    \e
+    const struct sockaddr_in *:                        \e
+        _Generic((t) NULL,                             \e
+        const struct sockaddr *:          (t) (p),     \e
+        default:                              (p)),    \e
+                                                       \e
+    struct sockaddr_in6 *:                             \e
+        _Generic((typeof_unqual(t)) NULL,              \e
+        struct sockaddr *:                (t) (p),     \e
+        default:                              (p)),    \e
+    struct sockaddr_in6 **:                            \e
+        _Generic((typeof_unqual(t)) NULL,              \e
+        struct sockaddr **:               (t) (p),     \e
+        default:                              (p)),    \e
+    const struct sockaddr_in6 *:                       \e
+        _Generic((t) NULL,                             \e
+        const struct sockaddr *:          (t) (p),     \e
+        default:                              (p)),    \e
+                                                       \e
+    struct sockaddr_un *:                              \e
+        _Generic((typeof_unqual(t)) NULL,              \e
+        struct sockaddr *:                (t) (p),     \e
+        default:                              (p)),    \e
+    struct sockaddr_un **:                             \e
+        _Generic((typeof_unqual(t)) NULL,              \e
+        struct sockaddr **:               (t) (p),     \e
+        default:                              (p)),    \e
+    const struct sockaddr_un *:                        \e
+        _Generic((t) NULL,                             \e
+        const struct sockaddr *:          (t) (p),     \e
+        default:                              (p)),    \e
+                                                       \e
+    default:                                           \e
+        (p)                                            \e
+    )
+
+socklen_t           slen;
+struct sockaddr_un  sun;
+
+slen = sizeof(ss);
+getsockname(sfd, sockaddr_cast(struct sockaddr *, &sun), &slen);
+.EE
+.PP
 The following program demonstrates how to write
 a replacement for the standard
 .BR imaxabs (3)
 function, which being a function can't really provide what it promises:
 seamlessly upgrading to the widest available type.
-.PP
+.IP
 .\" SRC BEGIN (_Generic.c)
 .EX
 #include <stdint.h>
-- 
2.38.1




[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