]> begriffs open source - libnonstd/blob - integral.h
Avoid the peril of signed integer promotion
[libnonstd] / integral.h
1 #ifndef LIBNONSTD_INTEGRAL_H
2 #define LIBNONSTD_INTEGRAL_H
3
4 #include <limits.h>
5 #include <stddef.h>
6 #include <stdint.h>
7
8 /* Integer bit patterns
9  *
10  * Purpose: bitwise operations and modular arithmetic.
11  *
12  * 6.2.5
13  *
14  *      A computation involving unsigned operands can never overflow, because a
15  *      result that cannot be represented by the resulting unsigned integer type
16  *      is reduced modulo the number that is one greater than the largest value
17  *      that can be represented by the resulting type.
18  *
19  * Each type "bN" is guaranteed to hold at least N bits.
20  *
21  * However, the types must be at least the size of int, or else they will be
22  * silently converted to signed int in any expression, and lose the unsigned
23  * guarantees.
24  *
25  * 6.3.1.1
26  *
27  *      If an int can represent all values of the original type, the value is
28  *      converted to an int; otherwise it is converted to an unsigned int.
29  */
30
31 typedef unsigned int       b16;
32 typedef unsigned long      b32;
33 typedef unsigned long long b64;
34
35 #define B16_MAX            UINT_MAX
36 #define B32_MAX            ULONG_MAX
37 #define B64_MAX            ULLONG_MAX
38
39 #define B16_C(n)           (n ## U)
40 #define B32_C(n)           (n ## UL)
41 #define B64_C(n)           (n ## ULL)
42
43 #define PRIdB16            "%u"
44 #define PRIdB32            "%lu"
45 #define PRIdB64            "%llu"
46
47 /* Regular (signed) integers
48  *
49  * Purpose: normal arithmetical operations and measurement, without modular
50  * arithmetic expectations.
51  *
52  * Care is required with these types to avoid overflow, which is undefined
53  * behavior.
54  *
55  * Each type "iN" is guaranteed to hold at least N bits, but may be wider if
56  * that would be faster for the processor. The "_trim" variety attempts to save
57  * space for e.g. big arrays.
58  */
59
60 typedef int           i8;
61 typedef signed char   i8_trim;
62
63 typedef int           i16;
64 typedef short         i16_trim;
65
66 typedef long          i32;
67 typedef int_least32_t i32_trim;
68
69 typedef long long     i64;
70 typedef int_least64_t i64_trim;
71
72 #define I8_MIN        INT_MIN
73 #define I8_MAX        INT_MAX
74 #define I8_TRIM_MIN   SCHAR_MIN
75 #define I8_TRIM_MAX   SCHAR_MAX
76 #define I16_MIN       INT_MIN
77 #define I16_MAX       INT_MAX
78 #define I16_TRIM_MIN  SHRT_MIN
79 #define I16_TRIM_MAX  SHRT_MAX
80 #define I32_MIN       LONG_MIN
81 #define I32_MAX       LONG_MAX
82 #define I32_TRIM_MIN  INT_LEAST32_MIN
83 #define I32_TRIM_MAX  INT_LEAST32_MAX
84 #define I64_MIN       LLONG_MIN
85 #define I64_MAX       LLONG_MAX
86 #define I64_TRIM_MIN  INT_LEAST64_MIN
87 #define I64_TRIM_MAX  INT_LEAST64_MAX
88
89 #define I8_C(n)       (n)
90 #define I16_C(n)      (n)
91 #define I32_C(n)      (n ## L)
92 #define I64_C(n)      (n ## LL)
93
94 #define PRIdI8        "%d"
95 #define PRIdI8_TRIM   "%hh"
96 #define PRIdI16       "%d"
97 #define PRIdI16_TRIM  "%h"
98 #define PRIdI32       "%ld"
99 #define PRIdI32_TRIM  PRIdLEAST32
100 #define PRIdI64       "%lld"
101 #define PRIdI64_TRIM  PRIdLEAST64
102
103 /* The size of data objects.
104  *
105  * This is a numerical quantity, not a bit pattern. Thus it fits into the
106  * signed integer category. This notion conflicts with the definition of
107  * size_t. We provide a signed counterpart, with wrappers for sizeof() and
108  * offsetof() that do bounds checking and convert the result.
109  *
110  * My conjecture is that size_t was chosen to be unsigned to wring the most out
111  * of each available bit on e.g. segmented 16-bit memory architectures.
112  */
113
114 #ifdef HAVE_SSIZE_T
115         // get ssize_t from POSIX
116         #include <sys/types.h>
117 #else
118         // make our best approximation
119         typedef ptrdiff_t ssize_t;
120         #define SSIZE_MAX PTRDIFF_MAX
121 #endif
122
123 #define PRIdSSIZE     "%td"
124
125 #define ssizeof(x) \
126         (sizeof(x) <= (size_t)SSIZE_MAX ? (ssize_t)sizeof(x) : -1)
127
128 #define soffsetof(t, m) \
129         (offsetof((t), (m)) <= (size_t)SSIZE_MAX ? offsetof((t), (m)) : -1)
130
131 /* Character types ********************************************************/
132
133 /* Character type 1: Smallest units of addressible storage.
134  *
135  * Purpose: load and store the raw aliased bytes of a C object.  it's a rare
136  * situation, used inside functions like memcpy or fwrite. Also, due to signed
137  * integer promotion, this type shouldn't be used in arithmetic operations.
138  *
139  * 6.2.6.1
140  *
141  *      Values stored in unsigned bit-fields *and objects of type unsigned char*
142  *      shall be represented using a pure binary notation.
143  *
144  *      Values stored in non-bit-field objects of any other object type consist of n
145  *      x CHAR_BIT bits, where n is the size of an object of that type, in bytes.
146  *      The value may be copied into an object of type unsigned char [n] (e.g., by
147  *      memcpy); the resulting set of bytes is called the object representation of
148  *      the value.
149  *
150  * 6.2.6.2
151  *
152  *      For unsigned integer types *other than unsigned char,* the bits of the
153  *      object representation shall be divided into two groups: value bits and
154  *      padding bits (there need not be any of the latter).
155  */
156
157 typedef unsigned char raw_byte;
158
159 /* Character type 2: Codepoints in a character encoding.
160  *
161  * The tasks of human language processing are too broad for a base language
162  * library, and the rules change as languages and locales do. Use a proper
163  * library for this, such as ICU, and its provided data types.
164  *
165  * - Note: pointers to native C string literals should be char*, as the
166  *   signedness of char is implementation-defined.
167  */
168
169 // No extra definitions for codepoints
170
171 /* Character type 3: Small integers.
172  *
173  * Already covered with i8 and i8_trim.
174  */
175
176 // No extra definitions for small integers
177
178 #endif