Writing a generic function to determine if an array of pointers contains NULL

I would like to write a generic function to determine if an array of pointers contains any arbitrary type of NULL . My initial attempt was as follows:

 bool find_null (void *ptrs, size_t num_ptrs) { void **array = ptrs; size_t i; for (i = 0; i < num_ptrs; ++i) { if (array[i] == NULL) return true; } return false; } 

It was pointed out that this could lead to severe violation of aliases, since an array of pointers to Foo will be available as an array of pointers to void , which is not specified as one of the permitted ways that an object is allowed to access in C.2011 & sect; 6.5 and para. 7.

I could rewrite the function to access the array of pointers as unsigned char * instead, but I'm not sure how to perform a NULL check without breaking a strict alias. Can someone provide valid technique?

 bool find_null (void *ptrs, size_t num_ptrs) { unsigned char *array = ptrs; void *p; size_t i; for (i = 0; i < num_ptrs; ++i) { memcpy(&p, array + i * sizeof(p), sizeof(p)); if (p == NULL) return true; /* * Above seems to still break strict aliasing. * What should be done instead? */ } return false; } 

The goal is to write a generic function that will work just like a type-specific function. In other words, the general version of the function is below:

 bool find_null_Foo (Foo *array[], size_t num_ptrs) { size_t i; for (i = 0; i < num_ptrs; ++i) { if (array[i] == NULL) return true; } return false; } 
+6
source share
3 answers

You cannot do this with the specific interface you represent, but you can do it somewhat awkwardly:

 bool find_null (const void *array, size_t num_ptrs, size_t ptr_size, const void *null) { const char (*ptr_array)[ptr_size] = array; size_t i; for (i = 0; i < num_ptrs; ++i) { if (!memcmp(array[i], null, ptr_size)) return true; } return false; } 

You would call it that:

 struct Foo; #define ARRAY_SIZE 53 int main(void) { struct Foo *my_array[ARRAY_SIZE] = { ... }; struct Foo * const foo_null = (struct Foo *) 0; if (find_null(my_array, ARRAY_SIZE, sizeof(*my_array), &foo_null)) { puts("It contains NULL"); } else { puts("It does not contain NULL"); } } 

Note that this assumes that there is only one representation for the null pointers of the type in question, which is true in many implementations, but not required by the language.

Please also note that this actually has nothing to do with finding null pointers, so you can actually use it to search your array of pointers for any pointer value. In fact, it is not even specific to pointer arrays - you can use it to search for any array for any value if byte-for-byte is equal to a suitable matching criterion (which it is not for structures or unions and may not be for some other types).

Also, if this suits you, you can probably develop a macro wrapper that makes it easier to use some of your more common scripts.

+1
source

Based on Raymond's comment , it seems that a generic function will require additional arguments. Since it is not possible to convert the representation of pointers from unsigned char pointers to void * , this must be done through a callback.

 bool find_null_generic (const void *ptrs, size_t ptr_sz, size_t num_ptrs, const void *(*convert)(const void *)) { const unsigned char *array = ptrs; size_t i; for (i = 0; i < num_ptrs; ++i) { if (convert(array + i * ptr_sz) == NULL) return true; } return false; } 

For a hypothetical array of a pointer to Foo :

 const void *convert_Foo (const void *data) { const Foo *foo; memcpy(&foo, data, sizeof(foo)); return foo; } Foo *foo_array[N] = {...}; bool result = find_null_generic(foo_array, sizeof(Foo *), N, convert_Foo); 
+1
source

The general function is not guaranteed, as expected, in systems where pointers to different types may have different representations and / or sizes. Fortunately, such architectures are now quite rare. For example, Posix-compatible systems guarantee the use of the same representation and size for all types of pointers.

+1
source

All Articles