I have two versions of a macro carray_at for bounds-checked array access, but the second one fails to compile with an error, while the first works.
First Macro (Works)
#define carray_at(arr, pos) \ ((((int)(pos) < 0 || (size_t)(pos) >= carray_size(arr)) ? NULL : &((arr).data[pos])) Second Macro (Fails)
#define carray_at(arr, pos) \ ((int)(pos) < 0 || (int)(pos) >= carray_size(arr) ? (printf("Index out of bounds: %d\n", (pos)), NULL) : &((arr).data[pos])) When used like *carray_at(arr, 1) = 5, it gives:
[root@gxnserver 09:35:03 lattice /$ gcc testa.c testa.c: In function 'main': testa.c:29:5: warning: dereferencing 'void *' pointer 29 | *carray_at(value1, 1) = 5; | ^ testa.c:29:27: error: invalid use of void expression 29 | *carray_at(value1, 1) = 5; | ^ Questions: Why does the first macro work while the second fails?
How does the fprintf + comma operator affect type inference in the ternary?
What’s the correct way to add error logging while maintaining dereferencability?
test code as follows:
#include <stdio.h> #include <assert.h> #include <stdbool.h> // define fixed size of array #define DEFINE_FIXED_ARRAY(TYPE, NAME, SIZE) \ typedef struct { \ TYPE data[SIZE]; \ size_t size; \ } NAME; #define carray_size(arr) \ (arr.size) // First Macro (Works) // #define carray_at(arr, pos) \ // ((((int)(pos) < 0 || (size_t)(pos) >= carray_size(arr)) ? NULL : &((arr).data[pos]))) // Second Macro (Fails) #define carray_at(arr, pos) \ ((int)(pos) < 0 || (int)(pos) >= carray_size(arr) ? (printf("Index out of bounds: %d\n", (pos)), NULL) : &((arr).data[pos])) #define ARRAY_SIZE 128 DEFINE_FIXED_ARRAY(int, IntArray, ARRAY_SIZE) int main(){ IntArray value1; *carray_at(value1, 1) = 5; return 0; }
((int)(pos)???? your size issize_t. Generally do not use macros like this.