Thomas Thomas - 1 month ago 14
C++ Question

Does Java have undefined behavior like C++ does?

Undefined behavior and sequence points

The link above is talking about sequence point and side effect in C++.


In a word, it means that between two sequence points, if we have more than one side effects, the order of the side effects are unspecified.


For example,

int x = 1;
int y = 2;
int z = x++ + y++;


What we can be sure is that
z
equals to 3. After
z
getting 3,
x
and
y
will increase --- there are two side effects so we don't know which one increases first.

Besides, the link above has listed all kinds of sequence points.

My question is, does Java has exactly the same case? I mean the same kinds of sequence points and the same undefined behaviors?

Answer

A major difference between "modern" C and C++, compared with most other popular languages, is that while other languages allow compilers to select among various corner-case behaviors in Unspecified fashion, the authors of the C and C++ Standard didn't want to constrain the languages to platforms where any kind of behavioral guarantee could be met easily.

Given a construct like:

int blah(int x)
{
  return x+10 > 20 ? x : 0;
}

Java precisely specifies the behavior for all values of x, including those which would cause integer wraparound; the design of early C compilers for two's-complement machines would yield the same behavior except that machines with different sizes of "int" (16 bit, 36 bit, etc.) would wrap at different places. Machines that use other representations for integers might behave differently, however.

Further, it would not have been uncommon for even "traditional" C compilers to behave as though the computations were performed on a longer type. Some machines had a few instructions that operated with longer types, and using those instructions and keeping values as longer types could sometimes be cheaper than truncating/wrapping values into the range of "int". On such machines, it would not be surprising for a function like the above to yield x even for values that were within 10 of overflowing. Note that Java tries to minimize behavioral differences among implementations, and thus does not generally allow even that level of behavioral variation.

Modern C, however, goes an extra step beyond Java. Not only does it allow for the possibility that compilers might arbitrarily keep excess precision with integer values, a modern compiler given a function like the above may infer that since the Standard would allow compilers to do anything whatsoever if a program receives inputs that would cause the function to receive a value of x greater than INT_MAX-10, a compiler should discard as irrelevant any code which would have no effect if such inputs are not received. The net effect of this is that integer overflow can disrupt the effect of preceding code in arbitrary fashion.

Java is thus two steps removed from Modern C's model of "Undefined Behavior"; it rigidly prescribes many more behaviors, and even in cases where behaviors are not rigidly defined implementations are still limited to choosing from among various possibilities. Unless one makes use of features in the Unsafe namespace or links Java with outside languages, Java programs will have much more constrained behavior, and even when using such constructs Java programs will still obey laws of time and causality in ways C programs may not.

Comments