1 /* PSPP - a program for statistical analysis. 2 Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc. 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation, either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17 #ifndef LIBPSPP_CAST_H 18 #define LIBPSPP_CAST_H 1 19 20 #include <stddef.h> 21 #include "gl/verify.h" 22 23 /* Expands to a void expression that checks that POINTER is an 24 expression whose type is a qualified or unqualified version of 25 a type compatible with TYPE (a pointer type) and, if not, 26 causes a compiler warning to be issued (on typical compilers). 27 28 Examples: 29 30 int *ip; 31 const int *cip; 32 const int **cipp; 33 int ***ippp; 34 double *dp; 35 36 // None of these causes a warning: 37 CHECK_POINTER_HAS_TYPE (ip, int *); 38 CHECK_POINTER_HAS_TYPE (ip, const int *); 39 CHECK_POINTER_HAS_TYPE (cip, int *); 40 CHECK_POINTER_HAS_TYPE (cip, const int *); 41 CHECK_POINTER_HAS_TYPE (dp, double *); 42 CHECK_POINTER_HAS_TYPE (dp, const double *); 43 CHECK_POINTER_HAS_TYPE (cipp, const int **); 44 CHECK_POINTER_HAS_TYPE (cipp, const int *const *); 45 CHECK_POINTER_HAS_TYPE (ippp, int ***); 46 CHECK_POINTER_HAS_TYPE (ippp, int **const *); 47 48 // None of these causes a warning either, although it is unusual to 49 // const-qualify a pointer like this (it's like declaring a "const int", 50 // for example). 51 CHECK_POINTER_HAS_TYPE (ip, int *const); 52 CHECK_POINTER_HAS_TYPE (ip, const int *const); 53 CHECK_POINTER_HAS_TYPE (cip, int *const); 54 CHECK_POINTER_HAS_TYPE (cip, const int *const); 55 CHECK_POINTER_HAS_TYPE (cipp, const int **const); 56 CHECK_POINTER_HAS_TYPE (cipp, const int *const *const); 57 CHECK_POINTER_HAS_TYPE (ippp, int ***const); 58 CHECK_POINTER_HAS_TYPE (ippp, int **const *const); 59 60 // Provokes a warning because "int" is not compatible with "double": 61 CHECK_POINTER_HAS_TYPE (dp, int *); 62 63 // Provoke warnings because C's type compatibility rules only allow 64 // adding a "const" qualifier to the outermost pointer: 65 CHECK_POINTER_HAS_TYPE (ippp, const int ***); 66 CHECK_POINTER_HAS_TYPE (ippp, int *const**); 67 */ 68 #define CHECK_POINTER_HAS_TYPE(POINTER, TYPE) \ 69 ((void) sizeof ((TYPE) (POINTER) == (POINTER))) 70 71 /* Given expressions A and B, both of which have pointer type, 72 expands to a void expression that causes a compiler warning if 73 A and B are not pointers to qualified or unqualified versions 74 of compatible types. 75 76 Examples similar to those given for CHECK_POINTER_HAS_TYPE, 77 above, can easily be devised. */ 78 #define CHECK_POINTER_COMPATIBILITY(A, B) ((void) sizeof ((A) == (B))) 79 80 /* Equivalent to casting POINTER to TYPE, but also issues a 81 warning if the cast changes anything other than an outermost 82 "const" or "volatile" qualifier. */ 83 #define CONST_CAST(TYPE, POINTER) \ 84 (CHECK_POINTER_HAS_TYPE (POINTER, TYPE), \ 85 (TYPE) (POINTER)) 86 87 /* Casts POINTER to TYPE. Yields a compiler diagnostic if either TYPE or 88 POINTER is not a pointer to character type. 89 90 PSPP uses "unsigned char" (actually uint8_t) in "union value" and "char" 91 elsewhere to emphasize that data in union value usually requires reencoding 92 when transferred to and from other string types. These macros suppress the 93 warning when implicitly converting between pointers to different character 94 types, so their use normally marks a bug that should eventually be fixed. 95 However, until these bugs are fixed, suppressing the warnings is much less 96 annoying. 97 98 Use CHAR_CAST_BUG if you think there is a bug to be fixed, or if you have 99 not yet carefully examined the situation, or if you are not sure. 100 Use CHAR_CAST if you are convinced that this is actually a correct cast. */ 101 #define CHAR_CAST(TYPE, POINTER) \ 102 ((void) verify_expr (sizeof (*(POINTER)) == 1, 1), \ 103 (void) (sizeof (*(POINTER) + 1)), \ 104 (void) verify_expr (sizeof (*(TYPE) NULL) == 1, 1), \ 105 (void) (sizeof (*(TYPE) NULL + 1)), \ 106 (TYPE) (POINTER)) 107 #define CHAR_CAST_BUG(TYPE, POINTER) CHAR_CAST(TYPE, POINTER) 108 109 /* Given POINTER, a pointer to the given MEMBER within structure 110 STRUCT, returns the address of the STRUCT. */ 111 #define UP_CAST(POINTER, STRUCT, MEMBER) \ 112 (CHECK_POINTER_COMPATIBILITY (&((STRUCT *) 0)->MEMBER, POINTER), \ 113 (STRUCT *) ((char *) (POINTER) - offsetof (STRUCT, MEMBER))) 114 115 /* A null pointer constant suitable for use in a varargs parameter list. 116 117 This is useful because a literal 0 may not have the same width as a null 118 pointer. NULL by itself is also insufficient because in C it may expand to 119 simply 0. */ 120 #define NULL_SENTINEL ((void *) NULL) 121 122 #endif /* libpspp/cast.h */ 123