]> git.ozlabs.org Git - ccan/blob - ccan/cast/cast.h
cast: fix cast of void * when we don't have GCC features.
[ccan] / ccan / cast / cast.h
1 #ifndef CCAN_CAST_H
2 #define CCAN_CAST_H
3 #include "config.h"
4 #include <stdint.h>
5 #include <ccan/build_assert/build_assert.h>
6
7 /**
8  * cast_signed - cast a (const) char * to/from (const) signed/unsigned char *.
9  * @type: some char * variant.
10  * @expr: expression (of some char * variant) to cast.
11  *
12  * Some libraries insist on an unsigned char in various places; cast_signed
13  * makes sure (with suitable compiler) that the expression you are casting
14  * only differs in signed/unsigned, not in type or const-ness.
15  */
16 #define cast_signed(type, expr)                                         \
17         ((type)(expr)                                                   \
18          + BUILD_ASSERT_OR_ZERO(cast_sign_compatible(type, (expr))))
19
20 /**
21  * cast_const - remove a const qualifier from a pointer.
22  * @type: some pointer type.
23  * @expr: expression to cast.
24  *
25  * This ensures that you are only removing the const qualifier from an
26  * expression.  The expression must otherwise match @type.
27  *
28  * If @type is a pointer to a pointer, you must use cast_const2 (etc).
29  *
30  * Example:
31  *      // Dumb open-coded strstr variant.
32  *      static char *find_needle(const char *haystack)
33  *      {
34  *              size_t i;
35  *              for (i = 0; i < strlen(haystack); i++)
36  *              if (memcmp("needle", haystack+i, strlen("needle")) == 0)
37  *                      return cast_const(char *, haystack+i);
38  *              return NULL;
39  *      }
40  */
41 #define cast_const(type, expr)                                          \
42         ((type)((intptr_t)(expr)                                        \
43                 + BUILD_ASSERT_OR_ZERO(cast_const_compat1((expr), type))))
44
45 /**
46  * cast_const2 - remove a const qualifier from a pointer to a pointer.
47  * @type: some pointer to pointer type.
48  * @expr: expression to cast.
49  *
50  * This ensures that you are only removing the const qualifier from an
51  * expression.  The expression must otherwise match @type.
52  */
53 #define cast_const2(type, expr)                                         \
54         ((type)((intptr_t)(expr)                                        \
55                 + BUILD_ASSERT_OR_ZERO(cast_const_compat2((expr), type))))
56
57 /**
58  * cast_const3 - remove a const from a pointer to a pointer to a pointer..
59  * @type: some pointer to pointer to pointer type.
60  * @expr: expression to cast.
61  *
62  * This ensures that you are only removing the const qualifier from an
63  * expression.  The expression must otherwise match @type.
64  */
65 #define cast_const3(type, expr)                                         \
66         ((type)((intptr_t)(expr)                                        \
67                 + BUILD_ASSERT_OR_ZERO(cast_const_compat3((expr), type))))
68
69
70 /**
71  * cast_static - explicit mimic of implicit cast.
72  * @type: some type.
73  * @expr: expression to cast.
74  *
75  * This ensures that the cast is not to or from a pointer: it can only be
76  * an implicit cast, such as a pointer to a similar const pointer, or between
77  * integral types.
78  */
79 #if HAVE_COMPOUND_LITERALS
80 #define cast_static(type, expr)                 \
81         ((struct { type x; }){(expr)}.x)
82 #else
83 #define cast_static(type, expr)                 \
84         ((type)(expr))
85 #endif
86
87 /* Herein lies the gcc magic to evoke compile errors. */
88 #if HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF
89 #define cast_sign_compatible(t, e) \
90   __builtin_choose_expr(                                                \
91           __builtin_types_compatible_p(__typeof__(t), char *) ||        \
92           __builtin_types_compatible_p(__typeof__(t), signed char *) || \
93           __builtin_types_compatible_p(__typeof__(t), unsigned char *), \
94           /* if type is not const qualified */                          \
95           __builtin_types_compatible_p(__typeof__(e), char *) ||        \
96           __builtin_types_compatible_p(__typeof__(e), signed char *) || \
97           __builtin_types_compatible_p(__typeof__(e), unsigned char *), \
98           /* and if it is... */                                         \
99           __builtin_types_compatible_p(__typeof__(e), const char *) ||  \
100           __builtin_types_compatible_p(__typeof__(e), const signed char *) || \
101           __builtin_types_compatible_p(__typeof__(e), const unsigned char *) ||\
102           __builtin_types_compatible_p(__typeof__(e), char *) ||        \
103           __builtin_types_compatible_p(__typeof__(e), signed char *) || \
104           __builtin_types_compatible_p(__typeof__(e), unsigned char *)  \
105           )
106
107 #define cast_const_strip1(expr)                 \
108         __typeof__(*(struct { int z; __typeof__(expr) x; }){0}.x)
109 #define cast_const_strip2(expr) \
110         __typeof__(**(struct { int z; __typeof__(expr) x; }){0}.x)
111 #define cast_const_strip3(expr) \
112         __typeof__(***(struct { int z; __typeof__(expr) x; }){0}.x)
113 #define cast_const_compat1(expr, type)                                  \
114         __builtin_types_compatible_p(cast_const_strip1(expr),           \
115                                      cast_const_strip1(type))
116 #define cast_const_compat2(expr, type)                                  \
117         __builtin_types_compatible_p(cast_const_strip2(expr),           \
118                                      cast_const_strip2(type))
119 #define cast_const_compat3(expr, type)                                  \
120         __builtin_types_compatible_p(cast_const_strip3(expr),           \
121                                      cast_const_strip3(type))
122 #else
123 #define cast_sign_compatible(type, expr)                \
124         (sizeof(*(type)0) == 1 && sizeof(*(expr)) == 1)
125 #define cast_const_compat1(expr, type)          (1)
126 #define cast_const_compat2(expr, type)          (1)
127 #define cast_const_compat3(expr, type)          (1)
128 #endif
129 #endif /* CCAN_CAST_H */