4

Consider this code:

int main()
{
    printf("Hello World!\n");
    int i;
    i = i++ + ++i; // UB
}

Is this code guaranteed to print "Hello World!"? The last line invokes undefined behavior, but does that invalidate the whole program?

I found this but that question is about C++. This is about C.

It's not a dup of Undefined behavior and sequence points since it's C++. The answer may or may not be the same, but this question is about C.

Community
  • 1
  • 1
klutt
  • 30,332
  • 17
  • 55
  • 95
  • 1
    I think I read somewhere a program with a line that causes undefined behavior is in fact a program with undefined behavior. Depending on the compiler optimizations weird stuff can happen before said line. – kabanus Sep 10 '18 at 09:23
  • @kabanus: This is about the standard as it seems. Compiler optimisations are beyond the standard. So relevant is the abstract machine which provides sequence points at best. However, apart from such artificial programs the question does not make much sense for production code. – too honest for this site Sep 10 '18 at 13:15
  • @toohonestforthissite I meant that the compiler do whatever it likes, but I see your point. – kabanus Sep 10 '18 at 16:00
  • @melpomene I added [A C specific answer that also covers C++](https://stackoverflow.com/a/52262732/1708801) so this is now a solid duplicate. – Shafik Yaghmour Sep 10 '18 at 19:09

1 Answers1

6

From the C standard (3.4.3) :

undefined behavior

behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements

Followed by :

NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

This means the standard does not impose any guarantees on the behavior of the entire program - including "earlier" operations.

Specific implementations however, might add certain guarantees for certain instances of undefined behavior (consult your compiler documentation eg.). And in practice, many implementations do behave in the way you describe for the most part. Optimizations tend to make this difficult to guarantee though. Additionally, compilers sometimes eliminate entire branches if they contain undefined behavior.

Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
  • 1
    Here are some practical examples of this actually happening: https://blog.regehr.org/archives/232 – melpomene Sep 10 '18 at 09:52
  • @melpomene: A quality implementation suitable for low-level programming on a particular target platform should allow for the possibility of a volatile access triggering any action that such an access could produce on that platform. If an implementation will never be used for low-level programming on a platform that defines the behavior of a particular volatile access as e.g. triggering a signal, then optimizing an unchecked divide across a volatile access would be appropriate. Such an assumption seems dodgy on implementations that claim to be suitable for use with for arbitrary platforms. – supercat Sep 10 '18 at 20:13