20

Possible Duplicate:
Why don’t languages raise errors on integer overflow by default?

Why doesn't C# use arithmetic overflow checking by default?

I figure that it would generally be better to have exceptions occur when this occurs so that errors aren't obscured. I know that it's occasionally useful to take advantage of the 'wrapping' behaviour that occurs, but the unchecked keyword could be used in these circumstances to make the intentions explicit.

I expect that this decision was made intentionally, perhaps to increase compatibility with other C-based languages.

Community
  • 1
  • 1
Sam
  • 40,644
  • 36
  • 176
  • 219
  • 4
    Probably for performance reasons - overflow checking is slow, and not needed in the vast majority of cases. – Richard Deeming Nov 06 '12 at 21:08
  • @MichaelPetito, thanks; that question seems better than this one, and it has good answers, so I think this should be closed. – Sam Nov 06 '12 at 21:53

2 Answers2

23

The C# Language Specification says this:

For non-constant expressions (expressions that are evaluated at run-time) that are not enclosed by any checked or unchecked operators or statements, the default overflow checking context is unchecked unless external factors (such as compiler switches and execution environment configuration) call for checked evaluation.

The reason for this choice is probably performance. I agree that this decision leads to errors among those who are not aware of "silent" integer overflow.

If your C# files belong to a C# project file (*.csproj), then that file holds configuration of the "default" overflow checking context. To changed it, see To set this compiler option in the Visual Studio development environment in this page.

If you don't use .csproj files, you're probably compiling everything from the command line, and then the above page tells you what command line option to use to set the default overflow checking context.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
2

See my answer to similar question here: Best way to handle Integer overflow in C#?

... there is a C# compiler option that defines how expressions outside of checked and unchecked are handled: /checked.

The default behavior is suitable for most applications. For other applications, where strict checking should be the default, there is a compiler option to enable such behavior.

Community
  • 1
  • 1
Michael Petito
  • 12,891
  • 4
  • 40
  • 54
  • 2
    Thanks for taking the time to answer, but I asked *why* rather than *how*. – Sam Nov 06 '12 at 21:11
  • 1
    @H2CO3 No, if I was designing a language, I'd default to wrap-around on overflow as well. Why? Because the performance impact of overflow checking is really **that** extreme. – Mysticial Nov 06 '12 at 21:13
  • @H2CO3, I asked why C# defaults to `unchecked` rather than `checked` behaviour. This answer describes *how* to use the `checked` keyword. I don't think that answers my question. – Sam Nov 06 '12 at 21:17
  • 3
    I'm not speaking for the downvote, I'm just saying that your implication that MS did it because they felt like it isn't correct. – Mysticial Nov 06 '12 at 21:17
  • The primary purpose of my answer was to illustrate that the default behavior, and why it was selected checked vs unchecked, is irrelevant because there is a compiler option to control the default behavior. – Michael Petito Nov 06 '12 at 21:18
  • @MichaelPetito, if you didn't intend to answer tha actual question, I think it would be more suitable to instead post a comment on the question. – Sam Nov 06 '12 at 21:20
  • @Sam This is an answer to your question, just perhaps not the one you were hoping. The question of *why* can certainly be answered *because there is an option to do otherwise*. – Michael Petito Nov 06 '12 at 21:26
  • @Mysticial: If a language's default behavior were to set a thread-static flag when an overflow occurs *which might result in a numerically-incorrect computation*, but allow a compiler flexibility in whether or not to report overflows in cases where a program would otherwise produce numerically-correct results, the performance overhead of compiler-generated overflow checks could in many cases be far less than the overhead of anything that could be done in user code. – supercat Apr 10 '17 at 23:37
  • 1
    @supercat The problem is that there's no way to efficiently implement that thread-static flag. On x86 at least, there is a flag register which is set on an overflow. But that gets overwritten by pretty much all operations. So you'd need to fetch and save that flag bit after most instructions - in which case, you've just added back all that overhead which you're trying to avoid. The only way checked arithmetic will be efficient is if it's implemented in the hardware. But that isn't the case with any mainstream processors. – Mysticial Apr 11 '17 at 00:08
  • @Mysticial: Much of the cost of overflow checking comes not from the branch-on-overflow instruction (overflow branches should have a low mis-prediction rate) but from the requirement that any arithmetic that might overflow must be performed before any operation that would be skipped in case of overflow. The semantics I described would allow a compiler to re-order calculations, skip any calculations which end up being ignored, and at its leisure substitute extended-precision calculations for overflow checking (e.g. when computing the sum of a bunch of 32-bit numbers, it may be faster to... – supercat Apr 11 '17 at 14:29
  • ...compute the sum as 64 bits and then check whether the result is in range, than to check for overflow at each step, and my proposed semantics would allow a compiler to make that substitution). Such optimizations wouldn't entirely eliminate the cost of overflow checking, but could probably cut it by half or more. – supercat Apr 11 '17 at 14:31
  • @supercat That would probably work better for languages that encourage the use of 32-bit integers (like Java) and less so for C or C++ that prefers `size_t` everywhere. A factor of 2 improvement is still a long way away from reaching the speed of no checking. The bigger problem is that once you've detected the overflow, it may be difficult to roll the computation back to the exact point where it happened so you can throw an exception from that point. In hardware that's easy to do via the bad same speculation rollback logic. But I'm not sure you can easily do that in software. – Mysticial Apr 11 '17 at 15:29
  • @Mysticial: If the primary overflow-detection semantics were via thread-static flag, there would be no *need* for such rollbacks. If code performs a bunch of computations within a loop and then either reports the computed value or reports that an overflow occurred, a compiler would be free to parallelize the loop whether or not it would be able to rollback any computations that might "follow" an overflow. – supercat Apr 11 '17 at 16:03
  • @supercat That would only work if the compiler can prove that a certain function or BB is a pure function. And given how bad aliasing analysis is, that probably rules out most of anything that touches memory. In any case, if you think default checked arithmetic will be at all efficient for normal code (not artificially crafted), feel free to demonstrate it. – Mysticial Apr 11 '17 at 16:41
  • @Mysticial: Checked arithmetic whose semantics are specified as throwing an exception without allowing any further code execution is going to be inefficient. If a language *specified* semantics with looser guarantees, the cost could be much lower while still allowing programmers to uphold the primary requirement (ensuring that results that overflow don't get falsely presented as valid). As a point of clarification, the flag would be maintained on a per-thread basis, but only accessible via special intrinsics; a compiler wouldn't have to worry about code taking its address. – supercat Apr 11 '17 at 18:55
  • @Mysticial: If a function performs a bunch of arithmetic operations and only tests the overflow flag at the end, the compiler wouldn't have to worry about rolling back anything. To avoid having programs waste time on calculations which were going to be useless, I'd include a variation of an overflow-test intrinsic which would include a number N, and say that a compiler could, at its leisure, skip the test unless it had skipped N previous tests. If e.g. N was 10,000 then the compiler could unroll or parallelize the loop in chunks of any convenient size, up to 10,000. – supercat Apr 11 '17 at 19:10