14
14
#ifndef FOSSIL_SYS_CNULLPTR_H
15
15
#define FOSSIL_SYS_CNULLPTR_H
16
16
17
- #include < stdint.h>
18
- #include < stddef.h>
19
- #include < assert.h>
17
+ #include < stdio.h>
18
+ #include < stdlib.h>
20
19
21
20
#ifdef __cplusplus
22
21
extern " C" {
23
22
#endif
24
23
25
- // Ensure null pointer is defined for compatibility with C11, C23, and C++ standards
24
+ /* *
25
+ * @brief A cross-platform, safe null pointer management library for C and C++.
26
+ *
27
+ * This library provides a set of macros and utilities to ensure consistent
28
+ * null pointer management across different versions of C and C++.
29
+ * It introduces safer, more expressive pointer handling inspired by concepts
30
+ * from modern programming languages like Rust, offering features like `Option`
31
+ * semantics, safe pointer casting, and enhanced error management.
32
+ *
33
+ * Key Features:
34
+ * - **Platform Agnostic Null Pointers:** Provides consistent `cnull` and `cnullptr`
35
+ * definitions across C and C++ using modern `nullptr` or fallback `void*` based
36
+ * null representation.
37
+ * - **Safe Pointer Manipulation:** Macros like `cnullify()`, `cnotnull()`, and
38
+ * `csafe_cast()` ensure safer memory management and prevent invalid pointer
39
+ * dereferences.
40
+ * - **Error Handling:** Offers expressive error management using `cpanic()` and
41
+ * `cunwrap()`, providing detailed error messages and file/line diagnostics.
42
+ * - **Optional Pointers:** Implements `COption`, a struct emulating Rust’s `Option<T>`
43
+ * with macros like `csome()`, `cnone()`, `cunwrap_option()`, and `cunwrap_or_option()`.
44
+ * - **Compile-Time Safety Hints:** Provides annotations like `cnullable` and `cnonnull`
45
+ * for static analysis, improving code safety by detecting null pointer misuse.
46
+ * - **Branch Prediction Optimization:** Includes `clikely()` and `cunlikely()` macros
47
+ * to optimize conditional branches based on runtime behavior.
48
+ * - **String Safety Constants:** Defines safe constants for null terminators,
49
+ * newline characters, and empty strings in both C and wide-character formats.
50
+ *
51
+ * Intended Usage:
52
+ * The library is suitable for scenarios requiring robust pointer management, particularly
53
+ * in low-level systems programming, embedded environments, and performance-critical
54
+ * applications. Developers transitioning from modern languages like Rust or C++ may
55
+ * find the familiar semantics helpful.
56
+ *
57
+ * Compatibility:
58
+ * - Supports **C11** and **C23** standards.
59
+ * - Fully compatible with **C++11** and later.
60
+ * - Provides graceful fallbacks for older compilers using `void*` based null pointers.
61
+ *
62
+ * Example Usage:
63
+ * ```c
64
+ * int* ptr = cnull;
65
+ * cnullify(ptr); // Safely set to null
66
+ *
67
+ * int* data = malloc(sizeof(int));
68
+ * *data = 42;
69
+ * COption opt = csome(data);
70
+ *
71
+ * int* result = (int*)cunwrap_option(opt); // Unwrap safely
72
+ * printf("Value: %d\n", *result);
73
+ *
74
+ * cdrop(data); // Nullify pointer safely
75
+ * ```
76
+ */
77
+
78
+ // Ensure null pointer definitions across C and C++ environments
26
79
#ifndef FOSSIL_CNULL
27
80
28
- #if __cplusplus >= 201103L || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
29
81
/* *
30
- * @brief Definition for cnull pointers in C++11 and later or C23 and later.
82
+ * @brief Safe and consistent null pointer definition for modern C++ and C standards.
83
+ *
84
+ * This section defines `cnull` and `cnullptr` for both C and C++ environments.
85
+ * The definitions ensure compatibility across different language versions, providing
86
+ * a clear and consistent way to represent null pointers.
87
+ *
88
+ * - **C++11 and Later:** If the code is compiled using C++11 (`__cplusplus >= 201103L`)
89
+ * or newer, `nullptr` is used. `nullptr` is a type-safe null pointer constant that
90
+ * prevents accidental misuse in pointer arithmetic or type ambiguities.
91
+ *
92
+ * - **C23 and Later:** In C23 (`__STDC_VERSION__ >= 202311L`), `nullptr` is introduced
93
+ * as a type-safe null pointer constant, mirroring the C++ equivalent. The `cnull`
94
+ * and `cnullptr` macros directly map to this standard definition.
95
+ *
96
+ * - **Older C Standards (C11 and Below):** If neither C23 nor C++11 is detected,
97
+ * `cnull` and `cnullptr` are defined using `((void*)0)`, which is the traditional
98
+ * and portable representation of a null pointer in C.
31
99
*
32
- * In C++11 or later, `cnullptr` is a keyword representing a cnull pointer constant.
33
- * In C23 or later, `_cnullptr` is recognized in the same way as C++.
100
+ * This abstraction guarantees that null pointer values are handled consistently
101
+ * across different compilers and platforms, reducing the risk of undefined behavior
102
+ * in pointer operations.
34
103
*/
104
+ #if __cplusplus >= 201103L || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
35
105
#define cnull nullptr
36
106
#define cnullptr nullptr
37
107
#else
38
- #if defined(_WIN64) || defined(_WIN32)
39
- /* *
40
- * @brief Definition for cnull pointers on Windows systems.
41
- *
42
- * For Windows (both 32-bit and 64-bit), we define `cnull` and `cnullptr` as 0.
43
- */
44
- #define cnull 0
45
- #define cnullptr 0
46
- #else
47
- /* *
48
- * @brief Definition for cnull pointers on POSIX systems, macOS, and embedded systems.
49
- *
50
- * For POSIX, macOS, and embedded systems, we define `cnull` and `cnullptr` as a void pointer to 0.
51
- */
52
- #define cnull (void *)(0 )
53
- #define cnullptr (void *)(0 )
54
- #endif
55
- #endif
108
+ #define cnull ((void *)0 )
109
+ #define cnullptr ((void *)0 )
56
110
#endif
57
111
112
+ #endif // FOSSIL_CNULL
113
+
58
114
/* *
59
- * @brief Macro to nullify a pointer.
60
- *
61
- * This macro sets a pointer to `cnull` (`nullptr` in C++ or platform-appropriate null in C).
62
- * It ensures that the pointer is safely assigned a null value.
63
- *
64
- * @param ptr The pointer to be nullified.
115
+ * @brief Nullify a pointer safely.
116
+ *
117
+ * Ensures that the pointer is explicitly set to `cnull`.
65
118
*/
66
119
#define cnullify (ptr ) ((ptr) = cnull)
67
120
68
121
/* *
69
- * @brief Checks if a pointer is not null.
70
- *
71
- * A macro that explicitly verifies if a pointer is not null before using it.
122
+ * @brief Check if a pointer is not null safely.
72
123
*
73
- * @param ptr The pointer to check.
74
- * @return 1 if not null, 0 otherwise.
124
+ * Prevents misuse of potentially null pointers.
75
125
*/
76
126
#define cnotnull (ptr ) ((ptr) != cnull)
77
127
78
128
/* *
79
- * @brief Represents an optional (nullable) value.
129
+ * @brief Option-like behavior to return a pointer or a default value.
80
130
*
81
- * If the value is null, it returns a default value instead.
82
- *
83
- * @param ptr The pointer to check.
84
- * @param default_val The default value to return if `ptr` is null.
85
- * @return `ptr` if not null, otherwise `default_val`.
131
+ * Mimics Rust's `Option::unwrap_or()` safely.
86
132
*/
87
- #define cmaybe (ptr, default_val ) ((ptr) ? (ptr) : (default_val))
133
+ #define cunwrap_or (ptr, default_val ) ((ptr) ? (ptr) : (default_val))
88
134
89
135
/* *
90
- * @brief Unwraps a pointer, asserting that it is not null.
91
- *
92
- * If the pointer is null, the program will terminate with an assertion failure.
93
- * Otherwise, it returns the pointer itself for safe dereferencing.
136
+ * @brief Unwraps a pointer safely or terminates if it's null.
94
137
*
95
- * @param ptr The pointer to unwrap.
96
- * @return The unwrapped pointer if it is not null.
138
+ * Mimics Rust's `Option::unwrap()`.
97
139
*/
98
- #define cunwrap (ptr ) (assert( (ptr) != cnull), (ptr ))
140
+ #define cunwrap (ptr ) ((cnotnull (ptr)) ? (ptr) : (fprintf(stderr, " Fatal error: called cunwrap() on a null pointer at %s:%d \n " , __FILE__, __LINE__), exit(EXIT_FAILURE), cnull ))
99
141
100
142
/* *
101
- * @brief Marks a variable as unused to suppress compiler warnings .
143
+ * @brief Safely casts one pointer type to another with null-checking .
102
144
*
103
- * Some compilers generate warnings when a variable is declared but not used.
104
- * This macro safely prevents such warnings without affecting the program .
145
+ * Mimics Rust's `as` with additional null safety. If the input is `cnull`,
146
+ * it returns `cnull` instead of attempting an invalid cast .
105
147
*
106
- * @param x The variable that is intentionally unused.
148
+ * @param type The target type for the cast.
149
+ * @param ptr The pointer to cast.
150
+ * @return The casted pointer or `cnull` if the input pointer is null.
151
+ */
152
+ #ifdef __cplusplus
153
+ #define csafe_cast (type, ptr ) ((cnotnull(ptr)) ? (static_cast <type>(ptr)) : cnull)
154
+ #else
155
+ #define csafe_cast (type, ptr ) ((cnotnull(ptr)) ? ((type)(ptr)) : cnull)
156
+ #endif
157
+
158
+ /* *
159
+ * @brief Marks a variable as intentionally unused to prevent warnings.
107
160
*/
108
161
#ifndef cunused
109
162
#if defined(__GNUC__) || defined(__clang__)
@@ -114,88 +167,136 @@ extern "C" {
114
167
#endif
115
168
116
169
/* *
117
- * @brief Annotations for nullable and nonnull pointers.
118
- *
119
- * These macros provide compiler hints about pointer validity, improving static analysis and safety.
170
+ * @brief Compiler hints for nullable and nonnull values.
120
171
*
121
- * - **GCC/Clang:** Uses `__attribute__((nullable))` and `__attribute__((nonnull))`
122
- * - **MSVC:** Uses `_Null_terminated_` and `_In_` (though `_In_` is not strictly equivalent to nonnull)
123
- * - **Fallback:** If the compiler does not support these attributes, it defines empty macros.
172
+ * Provides stronger safety checks at compile time.
124
173
*/
125
174
#if defined(__clang__) || defined(__GNUC__)
126
175
#define cnullable __attribute__ ((nullable))
127
176
#define cnonnull __attribute__ ((nonnull))
128
177
#elif defined(_MSC_VER)
129
- #define cnullable _Null_terminated_ // Not a perfect match, but useful for MSVC
130
- #define cnonnull _In_ // MSVC does not have a direct `nonnull` equivalent
178
+ #define cnullable _Null_terminated_
179
+ #define cnonnull _In_
131
180
#else
132
181
#define cnullable
133
182
#define cnonnull
134
183
#endif
135
184
136
- // Termination values for regular and wide strings
137
-
138
185
/* *
139
- * @brief Null-terminated character for C strings .
186
+ * @brief Compiler branch prediction hints for likely and unlikely conditions .
140
187
*
141
- * This is used as a constant for the null character in C strings, typically to represent the end of a string .
188
+ * Helps the compiler optimize branches based on expected conditions .
142
189
*/
143
- #define cterm ' \0 '
190
+ #if defined(__GNUC__) || defined(__clang__)
191
+ #define clikely (x ) __builtin_expect(!!(x), 1 )
192
+ #define cunlikely (x ) __builtin_expect(!!(x), 0 )
193
+ #else
194
+ #define clikely (x ) (x)
195
+ #define cunlikely (x ) (x)
196
+ #endif
197
+
198
+ // Safe string and character constants
144
199
145
200
/* *
146
- * @brief Null-terminated wide-character for wide strings.
147
- *
148
- * This is used as a constant for the null character in wide strings (`wchar_t` arrays), typically to represent the end of a wide string.
201
+ * @brief Null terminators for C and wide strings.
149
202
*/
203
+ #define cterm ' \0 '
150
204
#define wterm L' \0 '
151
205
152
- // Newline constants for regular and wide strings
206
+ /* *
207
+ * @brief Newline constants for C and wide strings.
208
+ */
209
+ #define cnewline ' \n '
210
+ #define wnewline L' \n '
211
+
212
+ /* *
213
+ * @brief Empty string constants for C and wide strings.
214
+ */
215
+ #define cempty " "
216
+ #define wempty L" "
217
+
218
+ /* *
219
+ * @brief Ensure safe cleanup by nullifying pointers after use.
220
+ *
221
+ * Mimics Rust's memory safety using explicit pointer management.
222
+ */
223
+ #define cdrop (ptr ) do { cnullify (ptr); } while (0 )
153
224
154
225
/* *
155
- * @brief Defines the newline character for C.
226
+ * @brief Panic behavior for immediate program termination with error message.
227
+ *
228
+ * This macro causes the program to immediately terminate with an error message,
229
+ * similar to Rust's `panic!()` functionality.
156
230
*
157
- * This is used in C and C++ environments for regular strings to denote a newline.
231
+ * @param msg The message to display when panicking.
232
+ */
233
+ #define cpanic (msg ) (fprintf(stderr, " Panic: %s\n " , msg), exit(EXIT_FAILURE))
234
+
235
+ /* *
236
+ * @brief Mimics Rust's Option type.
237
+ *
238
+ * The `coptional` macro represents a nullable pointer that can be either `cnull` or a valid pointer.
239
+ * It can be used to model optional values that may or may not be present.
158
240
*/
159
- #define cnewline ' \n '
241
+ #define coptional ( ptr ) ((ptr) ? (ptr) : cnull)
160
242
161
243
/* *
162
- * @brief Defines the newline character for wide strings in C and C++.
244
+ * @brief `COption` structure to mimic Rust's `Option<T>`.
245
+ *
246
+ * This structure allows representation of an optional value where it can either contain a value
247
+ * (`Some`) or be `None` (`cnull`).
248
+ */
249
+ typedef struct {
250
+ void * value; // The value held by the Option (could be a pointer to any type)
251
+ int is_some; // Flag indicating whether the Option is `Some` (1) or `None` (0)
252
+ } COption;
253
+
254
+ /* *
255
+ * @brief Creates an `Option` with a value (Some).
163
256
*
164
- * This is used for wide-character strings (`wchar_t`) to denote a newline.
257
+ * @param val The value to wrap in the Option.
258
+ * @return The created `COption` containing the value.
165
259
*/
166
- #define wnewline L' \n '
260
+ #ifdef __cplusplus
261
+ #define csome (val ) (COption{val, 1 })
262
+ #else
263
+ #define csome (val ) ((COption){(void *)(val), 1 })
264
+ #endif
167
265
168
266
/* *
169
- * @brief Defines an empty C string .
267
+ * @brief Creates an empty `Option` (None) .
170
268
*
171
- * This represents an empty string (`""`) for use in C and C++ code .
269
+ * @return An `Option` representing `None` .
172
270
*/
173
- #define cempty " "
271
+ #ifdef __cplusplus
272
+ #define cnone () (COption{cnull, 0 })
273
+ #else
274
+ #define cnone () ((COption){cnull, 0 })
275
+ #endif
174
276
175
277
/* *
176
- * @brief Defines an empty wide-character string.
278
+ * @brief Unwraps the `COption`. If it's `Some`, return the value; if it's `None`, panic.
279
+ *
280
+ * Mimics Rust's `Option::unwrap()`.
177
281
*
178
- * This represents an empty wide string (`L""`) for use in C and C++ code.
282
+ * @param opt The `COption` to unwrap.
283
+ * @return The value inside the `Option`.
179
284
*/
180
- #define wempty L" "
285
+ #define cunwrap_option ( opt ) ((opt).is_some ? (opt).value : (fprintf(stderr, " Panic: Unwrapped a None value at %s:%d \n " , __FILE__, __LINE__), exit(EXIT_FAILURE), cnull))
181
286
182
287
/* *
183
- * @brief Type-safe compiler attributes for null and nullable types .
288
+ * @brief Returns the value inside the `COption` or a default value if it's `None` .
184
289
*
185
- * - `cnull` and `cnullptr` handle null pointers across platforms.
186
- * - The constants `cterminator`, `wterminator`, `cterm`, `wterm` are used to represent the null terminators
187
- * for regular and wide-character strings.
188
- * - `cnewline` and `wnewline` are used to represent newline characters for regular and wide strings.
189
- * - `cempty` and `wempty` represent empty strings for regular and wide-character strings.
290
+ * Mimics Rust's `Option::unwrap_or()`.
190
291
*
191
- * These definitions ensure proper handling of string terminations and special characters across platforms.
192
- * Compiler-specific attributes:
193
- * - **GCC/Clang**: The use of `nullptr` for null pointers in C++ and null terminators for strings.
194
- * - **MSVC**: MSVC compilers do not natively support `nullptr` but handle `cnull` as 0.
292
+ * @param opt The `COption` to unwrap.
293
+ * @param default_val The default value to return if the `COption` is `None`.
294
+ * @return The value inside the `Option`, or the default value if `None`.
195
295
*/
296
+ #define cunwrap_or_option (opt, default_val ) ((opt).is_some ? (opt).value : (default_val))
196
297
197
298
#ifdef __cplusplus
198
299
}
199
300
#endif
200
301
201
- #endif
302
+ #endif // FOSSIL_SYS_CNULLPTR_H
0 commit comments