4 ms·
C, because reading uninitialized memory is undefined behavior so the compile can assume it never happens.
by jhasse 2y ago
C, because reading uninitialized memory is undefined behavior so the compile can assume it never happens.
- jeroenhd 2y agoBut wouldn't that change behavior? An empty, zero initialised array will contain data and a bunch of zeroes after a read, but if the next read only partially fills the buffer you end up with a buffer containing data from two reads. In this specific example there's no issue because the result of read() is being used to only write as much data as was read, but to me this seems like a pretty complicated and unlikely assumption to write optimizations for.
- vlovich123 2y agoCare to present some proof? Here’s an counter proof that the compiler isn’t able to reason about the memory in that way https://godbolt.org/z/x7j8xoMxY https://godbolt.org/z/x7j8xoMxY There are cases where C can do loop hoisting, but the cases are a subset of what Rust does and this isn’t one of those.
- uecker 2y agoYou example doesn't show this. Also the allocation is hoisted out of the loop. The initialization is not and this would be invalid in general. It could eliminated in this case, but this would be dead store elimination.
- vlovich123 2y agoThat’s identical to what happens on Rust. The allocation of the underlying uninitialized array is done once (it’s just the stack space allocation) and it assigns the value 0 within the body. It does indeed show exactly that what OP is proposing is something that C isn’t capable of and it’s what the entire article is about - the inability to skip the initialization in the first place by reasoning that it’s not needed.
- uecker 2y agoExcept it would be invalid to move the initialization out of the loop, so the example does not show whether a compiler could do this in principle.
- uecker 2y agoReading uninitialized memory is not undefined behavior.
- kbolino 2y agoAn explanation of why: https://stackoverflow.com/a/11965368/814422 https://stackoverflow.com/a/11965368/814422 There are some important caveats, though, around trap or non-value representations. Basically, the value held by the storage for a variable may not correspond to a valid value of the variable's type. For example, a bool variable usually takes a full byte but only has 2 valid representations in many ABIs (0 for false, 1 for true). That leaves 254 trap representations with 8-bit bytes, and trying to read any of these is undefined behavior. Furthermore, a variable may be stored in a register (unless you take its address with &), and registers can store values wider than the variable type--e.g., even though int has no trap representations in memory of the same size, nowadays it's usually smaller than a register--or be in a state that makes them unreadable. Trying to read such a value is also undefined behavior. So, reading memory in general is defined behavior (just with an indeterminate value) but it has to actually be memory and you have to be reading it into a type that can accept arbitrary bit patterns.