简体   繁体   中英

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?

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.

If it is not specified, then it's undefined and you have no guarantees.

Java is a language and therefore a specification exists: the so called JLS (Java Language Specification).

If something is not specified (like the order of the values of a HashMap) you can not expect to keep the order. The JLS in that case is similar to the Javadocs.

Correspondingly, if something is specified but the behavior is wrong, then that is a bug.

Your case is specified in the JLS, section 15.18 Additive Operators .

Expression evaluation results on a single Thread are completely specified in the Java Language Specification. There is no undefined behaviour in expression evaluation (on a single thread).

In C/C++, "undefined behaviour" means that anything may happen. If you put int z = x++ + y++; in your C program, the compiler may decide to generate code that formats you hard drive and it would still be compliant with the standard. There's nothing like that in Java either.

The behaviour of some constructs in a multi-threaded application may be non-deterministic (if not properly synchronized) but it isn't completely undefined either - it is clear what (out of a number of things) could happen if you don't properly synchronize the application - but you don't know which of the things from the list happen.

And there are some Java API's that don't define their result if you don't call them in a certain specified way. Their behaviour may vary from version to version in of the library, but usually the behaviour is consistent within the same version.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM