6 ms·
Even casting 0x12345678 to int* is undefined behavior
by hexane360 7y ago
Even casting 0x12345678 to int* is undefined behavior
- icedchai 7y agoThis happens all the time on embedded systems, when you're writing a device driver, etc. Practically speaking, it's well defined what will happen.
- NobodyNada 7y agoIt's implementation-defined, not undefined (see [0]). That means the behavior is well-defined by your implementation rather than by the C standard, so the code may work on one implementation but not on others. [0]: https://stackoverflow.com/q/2397984/3476191 https://stackoverflow.com/q/2397984/3476191
- nkurz 7y agoWhat makes you sure of this? I'm reasonably familiar with modern C, but I don't feel confident of the answer here. A search of Stackoverflow doesn't bring up anything that seems authoritative for C. The most relevant quotation I can find is in the Rational for C99, where Section 6.3.2.3 has: Implicit in the Standard is the notion of invalid pointers. In discussing pointers, the Standard typically refers to “a pointer to an object” or “a pointer to a function” or “a null pointer.” A special case in address arithmetic allows for a pointer to just past the end of an array. Any other pointer is invalid. An invalid pointer might be created in several ways. An arbitrary value can be assigned (via a cast) to a pointer variable. (This could even create a valid pointer, depending on the value.) A pointer to an object becomes invalid if the memory containing the object is deallocated or moved by realloc. Pointer arithmetic can produce pointers outside the range of an array. Regardless how an invalid pointer is created, any use of it yields undefined behavior. Even assignment, comparison with a null pointer constant, or comparison with itself, might on some systems result in an exception. I'm not a language lawyer, but I suspect this means that even initialization to the wrong literal might well be undefined behavior. What makes you confident that it's not, and instead is merely implementation defined?
- icedchai 7y agoI found this: https://stackoverflow.com/questions/51083356/does-the-c-standard-permit-assigning-an-arbitrary-value-to-a-pointer-and-increme https://stackoverflow.com/questions/51083356/does-the-c-stan... What if it's not an "invalid pointer", but a pointer to a memory-mapped IO address, ROM, etc? I grew up learning C on 16-bit machines in the early 90's. Hard coded pointer values were very, very common.
- nkurz 7y agoGood find! I don't think there is anything "authoritative" there, but the discussion seems high quality. My take is that a lot of smart people disagree on which parts of that example are implementation-defined, implementation-undefined(!), or undefined-behavior. Most (but not all) think that the initial assignment is implementation defined, but 'davislor' suggests in his answer that "the line void * ptr = (char * )0x01; is already potentially undefined behavior, on an implementation where (char* )0x01 or (void* )(char* )0x01 is a trap representation". > What if it's not an "invalid pointer", but a pointer to a memory-mapped IO address, ROM, etc? Yes, this is central to the question. And how is the compiler to know? Is it safe to presume that the compiler can't know, and thus can't presume undefined behavior? I think the answer is in the comments you linked where 'supercat' replies to 'Peter Cordes': The Standard makes no attempt to mandate that all implementations be suitable for low-level systems programming, nor does it in any way imply that it's possible to have a quality implementation that is suitable for low-level or systems programming without it supporting behaviors beyond those mandated by the Standard (and which might not be processed predictably by implementations that aren't suitable for systems programming). Which is to say, yes, for a compiler implementation to actually be useful for low-level programming, it must behave in a predictable manner when given literal addresses. Unfortunately, it may be possible for a C compiler to be "standards conforming" without actually being useful for this purpose. One can only hope that at least some compilers will continue to "do the right thing" despite that lack of explicit requirements.
- comex 7y ago> Unfortunately, it may be possible for a C compiler to be "standards conforming" without actually being useful for this purpose. It is possible for a C implementation to be conforming witout supporting low-level programming. Sometimes it even makes sense, like if you're running C code on GraalVM's LLVM bitcode interpreter. But there is no trend of "standard" C implementations following this route. While modern C compilers like to aggressively exploit undefined behavior, they generally make reasonable decisions for implementation-defined behavior. In this case, all major compilers will compile *(int*)0x12345678 to the obvious assembly, and what happens then depends on what your memory map looks like. (Caveat: the compiler will still perform normal optimizations like removing unused loads or redundant stores. If the address actually points to memory-mapped I/O, you need `volatile` to prevent that.)