6 ms·
More like, "if you do this, what happens depends on your particular combination of hardware, operating system, and compiler. Don't ask us."
by professoretc 4mo ago
More like, "if you do this, what happens depends on your particular combination of hardware, operating system, and compiler. Don't ask us."
- nickez 4mo agoNo, that would be implementation defined.
- tekne 4mo agoNo, that's actually UB. The important bit here is "compiler defined" -- UB means the compiler is allowed to assume it never happens while compiling. Consider, for example, an implementation defined function f() -- which can also diverge/crash horribly, etc. If I write if p { print("p is true") } else { g() } if p { f() } Then either we: - print p is true and execute f - do nothing This is true regardless of if f immediately crashes the computer, nasal demons, whatever -- that's implementation defined. UB means f may never happen. And that means the compiler may optimize this to just: g() Notice the difference here -- the print never happens!, and g always happens. You can see why this is concerning when you write code like if dry_run { print("would run rm -rf /") } else { run("rm -rf /") } if dry_run { // oops: some_debug_string is NULL and will segfault! print(some_debug_string); }
- tyg13 4mo agoI see what you're going for, but I don't see how your example is UB. If `p` is a pointer, and, after your `if (p)` check, `p` is dereferenced unconditionally, then yes, your check for `p == NULL` could be removed, and the code under the `if` would be removed as well. But the example you've constructed is not UB.
- Quekid5 4mo agoYou misunderstood their example, I think. If doesn't matter what 'p' is in their example. The point is: if 'f' is undefined behavior (rather than just impl-defined), then the optimizer concludes that the "if p { f() }" can never happen... which means that we're allowed to assume that 'if p { ... } else { ... }' (in the first part of the example) will always take the else branch. The compiler will optimize accordingly and just always call g() unconditionally.
- professoretc 4mo agoThe post I was replying to said, > UB was coined only in the first C standard, in 1989. Prior to that there was no "If you do this, anything can happen". I.e., the context is, before UB existed as a concept, how would these things be categorized. And I was trying to offer the correction that, before UB existed, it wasn't "all behavior is defined" but rather many behaviors depend on your particular local environment. While that may technically be implementation defined, the current standard requires that implementation defined be documented, and UB-like edge cases were most definitely not documented anywhere consistently in the old days!