There is no guarantee in the standard that if ptr is a null pointer, then (uintptr_t)ptr is 0 .
If you do not need systems for which null pointers and zero integers are not equivalent, then info.init = 0; excellent.
The init element is an integer type; it cannot be "made null". You can assign it 0 , or you can assign it the result of converting a null pointer to uintptr_t . In almost all C implementations, all of this is one and the same. But this is not guaranteed, and there were systems on which it is not the same.
NULL may be a null pointer, or it may be an integer constant of 0 . In the latter case, the standard guarantees that (uintptr_t)(NULL) 0 . Thus, there may be implementations on which info.init = NULL; (void*)(info.init); info.init = NULL; (void*)(info.init); has undefined behavior. This will not result in a null pointer if the integer equivalent null is not 0, and the calculation of the invalid pointer value is UB.
So, if you want to ensure that info , when converted to a pointer type, outputs a null pointer, then for true portability you should do info.init = (uintptr_t)(void*)(NULL); . You could additionally provide the reader with additional help by specifying the type of pointer to be converted by uintptr_t , not void* . There are very few good reasons to store uintptr_t , so hints about what happens can help the reader.
Note that there is a guarantee in the standard that a constant null value converted to a pointer type is a null pointer. This does not mean that a null undefined expression converted to a pointer type is a null pointer. Also, this does not mean that the null pointer, converted to an integer type, is 0. These last two things happen in most implementations (including all "modern" ones).
source share