X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flibpspp%2Fcast.h;h=00e42d6603cc68963f498c6d5ce0ab780c1b19f6;hb=49c02dd0d35698fd43528c4422b3b5202b481a11;hp=f74442c2cea7cb4f99c85d2a6fb3d1e026505f68;hpb=12895f38b01137ae0b14f07d26e6f0928b735bdf;p=pspp diff --git a/src/libpspp/cast.h b/src/libpspp/cast.h index f74442c2ce..00e42d6603 100644 --- a/src/libpspp/cast.h +++ b/src/libpspp/cast.h @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 2009 Free Software Foundation, Inc. + Copyright (C) 2009, 2010 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,17 +18,105 @@ #define LIBPSPP_CAST_H 1 #include +#include "gl/verify.h" + +/* Expands to a void expression that checks that POINTER is an + expression whose type is a qualified or unqualified version of + a type compatible with TYPE (a pointer type) and, if not, + causes a compiler warning to be issued (on typical compilers). + + Examples: + + int *ip; + const int *cip; + const int **cipp; + int ***ippp; + double *dp; + + // None of these causes a warning: + CHECK_POINTER_HAS_TYPE (ip, int *); + CHECK_POINTER_HAS_TYPE (ip, const int *); + CHECK_POINTER_HAS_TYPE (cip, int *); + CHECK_POINTER_HAS_TYPE (cip, const int *); + CHECK_POINTER_HAS_TYPE (dp, double *); + CHECK_POINTER_HAS_TYPE (dp, const double *); + CHECK_POINTER_HAS_TYPE (cipp, const int **); + CHECK_POINTER_HAS_TYPE (cipp, const int *const *); + CHECK_POINTER_HAS_TYPE (ippp, int ***); + CHECK_POINTER_HAS_TYPE (ippp, int **const *); + + // None of these causes a warning either, although it is unusual to + // const-qualify a pointer like this (it's like declaring a "const int", + // for example). + CHECK_POINTER_HAS_TYPE (ip, int *const); + CHECK_POINTER_HAS_TYPE (ip, const int *const); + CHECK_POINTER_HAS_TYPE (cip, int *const); + CHECK_POINTER_HAS_TYPE (cip, const int *const); + CHECK_POINTER_HAS_TYPE (cipp, const int **const); + CHECK_POINTER_HAS_TYPE (cipp, const int *const *const); + CHECK_POINTER_HAS_TYPE (ippp, int ***const); + CHECK_POINTER_HAS_TYPE (ippp, int **const *const); + + // Provokes a warning because "int" is not compatible with "double": + CHECK_POINTER_HAS_TYPE (dp, int *); + + // Provoke warnings because C's type compatibility rules only allow + // adding a "const" qualifier to the outermost pointer: + CHECK_POINTER_HAS_TYPE (ippp, const int ***); + CHECK_POINTER_HAS_TYPE (ippp, int *const**); +*/ +#define CHECK_POINTER_HAS_TYPE(POINTER, TYPE) \ + ((void) sizeof ((TYPE) (POINTER) == (POINTER))) /* Given expressions A and B, both of which have pointer type, expands to a void expression that causes a compiler warning if A and B are not pointers to qualified or unqualified versions - of compatible types. */ + of compatible types. + + Examples similar to those given for CHECK_POINTER_HAS_TYPE, + above, can easily be devised. */ #define CHECK_POINTER_COMPATIBILITY(A, B) ((void) sizeof ((A) == (B))) +/* Equivalent to casting POINTER to TYPE, but also issues a + warning if the cast changes anything other than an outermost + "const" or "volatile" qualifier. */ +#define CONST_CAST(TYPE, POINTER) \ + (CHECK_POINTER_HAS_TYPE (POINTER, TYPE), \ + (TYPE) (POINTER)) + +/* Casts POINTER to TYPE. Yields a compiler diagnostic if either TYPE or + POINTER is not a pointer to character type. + + PSPP uses "unsigned char" (actually uint8_t) in "union value" and "char" + elsewhere to emphasize that data in union value usually requires reencoding + when transferred to and from other string types. These macros suppress the + warning when implicitly converting between pointers to different character + types, so their use normally marks a bug that should eventually be fixed. + However, until these bugs are fixed, suppressing the warnings is much less + annoying. + + Use CHAR_CAST_BUG if you think there is a bug to be fixed, or if you have + not yet carefully examined the situation, or if you are not sure. + Use CHAR_CAST if you are convinced that this is actually a correct cast. */ +#define CHAR_CAST(TYPE, POINTER) \ + ((void) verify_true (sizeof (*(POINTER)) == 1), \ + (void) (sizeof (*(POINTER) + 1)), \ + (void) verify_true (sizeof (*(TYPE) NULL) == 1), \ + (void) (sizeof (*(TYPE) NULL + 1)), \ + (TYPE) (POINTER)) +#define CHAR_CAST_BUG(TYPE, POINTER) CHAR_CAST(TYPE, POINTER) + /* Given POINTER, a pointer to the given MEMBER within structure STRUCT, returns the address of the STRUCT. */ #define UP_CAST(POINTER, STRUCT, MEMBER) \ (CHECK_POINTER_COMPATIBILITY (&((STRUCT *) 0)->MEMBER, POINTER), \ (STRUCT *) ((char *) (POINTER) - offsetof (STRUCT, MEMBER))) +/* A null pointer constant suitable for use in a varargs parameter list. + + This is useful because a literal 0 may not have the same width as a null + pointer. NULL by itself is also insufficient because in C it may expand to + simply 0. */ +#define NULL_SENTINEL ((void *) NULL) + #endif /* libpspp/cast.h */