Typecasting NULL pointer in C

2019-04-29 16:29发布

问题:

I have a structure

struct detail {
int id;
uintptr_t init;
// blah blah
};
struct detail info;
info.id = 1;
info.init = (uintptr_t)NULL;

I have to make the the init member NULL. What may/may not happen if I typecast(or do not typecast) NULL ? What if I directly assign it NULL like info.init = NULL; Does it make any difference with respect to runtime errors. It compiles fine. But the execution of the code is my main concern.

Thanks

回答1:

There is no guarantee in the standard that if ptr is a null pointer, then (uintptr_t)ptr is 0.

If you don't care about systems on which null pointers and zero integers aren't equivalent, then info.init = 0; is fine.

The init member has integer type, it cannot be "made null". You can assign 0 to it, or you can assign to it the result of converting a null pointer to uintptr_t. On almost every C implementation ever, those are the same thing. But it is not guaranteed, and there have been systems on which it is not the same.

NULL might be a null pointer, or it might be an integer constant 0. In the latter case, there is a guarantee in the standard that (uintptr_t)(NULL) is 0. So there can be implementations on which info.init = NULL; (void*)(info.init); has undefined behavior. It wouldn't result in a null pointer if the integer equivalent of null isn't 0, and computing an invalid pointer value is UB.

So, if you want to guarantee that info, when converted to a pointer type, results in a null pointer then for true portability you should do info.init = (uintptr_t)(void*)(NULL);. You could optionally give the reader an extra clue by including the pointer type that the uintptr_t is going to be converted to, instead of void*. There are very few good reasons for storing a uintptr_t, so hints what is going on might help the reader.

Note that there is a guarantee in the standard that a zero-valued constant expression, converted to pointer type, is a null pointer. This does not imply that a zero-valued non-constant expression, converted to a pointer type, is a null pointer. Neither does it imply that a null pointer, converted to integer type, is 0. Those last two things happen to be true in most implementations (including all "modern" ones).



回答2:

NULL is a built in constant with a value matching whatever a null pointer is on your system. It's perfectly valid to assign the constant value to an int the same size (or bigger) than a pointer on your system.



回答3:

I would vote for the cast here, since assigning pointers to integers is generally not allowed and will generate a warning. It's a very good idea to use intptr_t of course, since it's big enough.