Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

71%
+3 −0
Q&A Casting a non-`void` pointer to `uintptr_t`

If reading the standard strictly by the letter then you are correct. And therefore both CERT and MISRA are picky with these kind of conversions because they strive to cover all poorly-defined behav...

posted 1d ago by Lundin‭

Answer
#1: Initial revision by user avatar Lundin‭ · 2025-03-03T07:59:30Z (1 day ago)
If reading the standard strictly by the letter then you are correct. And therefore both CERT and MISRA are picky with these kind of conversions because they strive to cover all poorly-defined behavior.

However, I think this is one of the cases when one can assume a sensible compiler implementation. And the MISRA rule forbidding conversions like these is on my permanent deviation list, because it is simply not practical when doing hardware-related programming.

In order for a `void*` to be convertible from any other object pointer and back, the only sensible implementation in practice is for all object pointers to have the same size and presentation. It's not mandated by the C standard that they are, but to solve the conversion requirement in any other way would be strange and cumbersome. 

Therefore it is fairly safe to assume that we can convert directly to/from `uintptr_t` to any object pointer type. The main reason `uintptr_t` exists is because of situations when the address bus is of a different size than the CPU word size and the code needs to be portable.

The reason why other integer to/from pointer types is implementation-defined is because of several reasons: pointer size as mentioned above, but also alignment and hardware limitations. An integer can hold any value - not necessarily corresponding to an aligned address of the pointer type we covert it to. Furthermore there are of course a lot of hardware restrictions requiring that the address must be one where an object is allowed to be stored.

Also the wording in the standard is "An integer may be converted to any pointer type" meaning both object pointers and function pointers.

The `void*` can be allowed to be more lenient than that, because it has the same alignment (none) as a character type (ISO C23 6.25), it is always an object pointer and it is never directly used for de-referencing an actual object.

C has never made an explicit guarantee that various pointer types have the same representation or size. However this is one of those cases when they thought they made the language more portable with a lenient wording, yet on targets where it actually matters, every compiler I know of has _not_ taken advantage of this. Rather, on system with extended addressing, non-standard extensions `near`/`far` are used as pointer qualifiers to state if the pointer is in the normal or extended address space. So the flexibility made possible by vague wording in ISO C23 6.3.3.3 (previously 6.3.2.3) isn't actually used in practice.

So while not required by the C standard, in practice we can very likely convert directly to/from `uintptr_t` and everyone is using the type like that too. I use it for function pointers too - out of all integer types, it is the best and most portable one. I also have yet to encounter a (post C99) compiler which does not implement it.