From: Alejandro Colomar <alx.manpages@gmail.com>
To: linux-man@vger.kernel.org
Cc: Alejandro Colomar <alx@kernel.org>,
Andrew Clayton <andrew@digital-domain.net>
Subject: [PATCH v6] _Generic.3: EXAMPLES: Add sockaddr_cast() macro
Date: Sat, 12 Nov 2022 00:06:44 +0100 [thread overview]
Message-ID: <20221111230643.10764-1-alx@kernel.org> (raw)
In-Reply-To: <c583b742-9582-ceaa-aaf7-097cecb78a2e@gmail.com>
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) \
)
However, qual_cast() is less useful in quality code, since it breaks const
correctness. It's only useful to interface dubious APIs.
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@digital-domain.net>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
---
man3/_Generic.3 | 113 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 112 insertions(+), 1 deletion(-)
diff --git a/man3/_Generic.3 b/man3/_Generic.3
index ddee5f6c4..740b7b358 100644
--- a/man3/_Generic.3
+++ b/man3/_Generic.3
@@ -27,12 +27,123 @@ .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
+ struct sockaddr_storage *: \e
+ _Generic((typeof_unqual(t)) NULL, \e
+ struct sockaddr *: (t) (p), \e
+ struct sockaddr_in *: (t) (p), \e
+ struct sockaddr_in6 *: (t) (p), \e
+ struct sockaddr_un *: (t) (p), \e
+ default: (p)), \e
+ struct sockaddr_storage **: \e
+ _Generic((typeof_unqual(t)) NULL, \e
+ struct sockaddr **: (t) (p), \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_storage *: \e
+ _Generic((t) NULL, \e
+ const struct sockaddr *: (t) (p), \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
+ default: \e
+ (p) \e
+ )
+
+socklen_t slen;
+struct sockaddr_storage ss;
+
+slen = sizeof(ss);
+getsockname(sfd, sockaddr_cast(struct sockaddr *, &ss), &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
next prev parent reply other threads:[~2022-11-11 23:08 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-11-11 14:53 _Generic.3: EXAMPLES: C++'s static_cast() in C Alejandro Colomar
2022-11-11 15:11 ` Alejandro Colomar
2022-11-11 16:54 ` Alejandro Colomar
2022-11-11 17:08 ` Alejandro Colomar
2022-11-11 21:40 ` Alejandro Colomar
2022-11-11 23:06 ` Alejandro Colomar [this message]
2022-11-12 14:15 ` [PATCH v7] _Generic.3: EXAMPLES: Add sockaddr_cast() macro Alejandro Colomar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20221111230643.10764-1-alx@kernel.org \
--to=alx.manpages@gmail.com \
--cc=alx@kernel.org \
--cc=andrew@digital-domain.net \
--cc=linux-man@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox