summaryrefslogtreecommitdiffstats
path: root/man3/_Generic.3
blob: 6ff5e24ea76a871fb3fb1c9f510ead406bdb58a6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
.\" Copyright (C) 2022 Alejandro Colomar <alx@kernel.org>
.\"
.\" SPDX-License-Identifier: Linux-man-pages-copyleft
.\"
.TH _Generic 3 (date) "Linux man-pages (unreleased)"
.SH NAME
_Generic \- type-generic selection
.SH SYNOPSIS
.nf
.BR _Generic( \fIexpression\fP ", type1: " e1 ", " "... /*" \
", default: " "e */" );
.fi
.SH DESCRIPTION
.BR _Generic ()
evaluates the path of code under the type selector
that is compatible with the type of the controlling
.IR expression ,
or
.B default:
if no type is compatible.
.PP
.I expression
is not evaluated.
.PP
This is especially useful for writing type-generic macros,
that will behave differently depending on the type of the argument.
.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.
.IP
.\" SRC BEGIN (_Generic.c)
.EX
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#define my_imaxabs  _Generic(INTMAX_C(0),  \e
    long:           labs,                  \e
    long long:      llabs                  \e
 /* long long long: lllabs */              \e
)

int
main(void)
{
    off_t  a;

    a = \-42;
    printf("imaxabs(%jd) == %jd\en", (intmax_t) a, my_imaxabs(a));
    printf("&imaxabs == %p\en", &my_imaxabs);
    printf("&labs    == %p\en", &labs);
    printf("&llabs   == %p\en", &llabs);

    exit(EXIT_SUCCESS);
}
.EE
.\" SRC END