0

A c programming book that I'm reading(c programming, a modern approach 2nd edition) says that when an "overflow occurs during an operation on unsigned integers, though, the result is defined."

Here is a small code example

#include <stdio.h>

int main()
{
  unsigned short int x = 65535; // The unsigned short int is at the maximum possible range
  x += 1; // If I add one to it will overflow.
  printf("%u", x); // the output will be zero or one if decide to add plus one again to x
  return 0;
}

He then goes to say that "for signed integers, the behaviors for these integers are not defined". Meaning the program can either print out the incorrect result or it can crash the program.

Why is this so?

Luis Averhoff
  • 385
  • 6
  • 22
  • 1
    Are you asking why the behaviour of signed integer overflow is undefined, (*because the language specification says it is*), or why the specification defines unsigned integer overflow but declares signed integer overflow to be undefined (*[different representations of signed values](http://stackoverflow.com/questions/18195715/why-is-unsigned-integer-overflow-defined-behavior-but-signed-integer-overflow-is)*)? Also, please don't print unsigned values with `%d` - `%u` exists for a reason. – Iskar Jarak May 08 '15 at 22:34
  • @IskarJarak "why the specification defines unsigned integer overflow but declares signed integer overflow to be undefined?" This part of your sentence is what I'm asking. – Luis Averhoff May 08 '15 at 22:38
  • @LuisAverhoff See the duplicate link then. This has been asked before. – Iskar Jarak May 08 '15 at 22:38
  • @IskarJarak Alright, I also changed it to %u instead of %d. – Luis Averhoff May 08 '15 at 22:39
  • @LuisAverhoff Great. Since you're printing an unsigned _short_, you could also consider `%hu` instead, although `%u` should work fine anyway. – Iskar Jarak May 08 '15 at 22:41

1 Answers1

3

It comes down to hardware representation, and there being more than one way to represent signed integral types in binary (sign magnitude, ones complement, twos complement) and operations on them. Those have quite different implications when an overflow occurs (e.g. triggering a hardware trap, working with modulo, etc).

All of the obvious means of representing unsigned integral values in binary and implementing numerical operations on such values have the same consequence - essentially that numeric operations in hardware work with a modulo arithmetic.

For basic types (and other things) the standard generally allows freedom to compiler vendors when there is more than one feasible way of implementing something, and those options have different consequences. There are multiple ways with signed integral types, and real-world hardware that uses each approach. They are different enough to warrant the behaviour being undefined (as that term is defined in the standard).

Peter
  • 35,646
  • 4
  • 32
  • 74
  • This answer is totally correct. It is also worth mentioning that, unfortunately, because the standard says the behavior is undefined, that leaves compiler vendors open to do *anything*. Overflowing a signed int via addition in C doesn't necessarily have to do what your CPU's ADD instruction does on overflow. Optimizers have been known to exploit this undefinedness and optimize away the addition entirely. IMO this is a dangerous game to be playing with the spec. – StilesCrisis May 09 '15 at 00:23
  • True. I'll think about it, but my first thought is that this is going a bit far afield given the original question. What you describe is the sort of self-fulfilling prophecy sometimes associated with undefined behaviour (something is undefined in standard because of an existing range of real-world behaviours then, because it is undefined, implementers choose to support even more possible behaviours). However, that is a consequence of something being undefined, not the reason it was left undefined in the first place. – Peter May 09 '15 at 02:19
  • Well, for me, the obvious inference from "it's undefined because different CPUs have different behaviors" is that "the C compiler will follow the behavior of my CPU architecture", but the reality is far more subtle. It's a trap. – StilesCrisis May 09 '15 at 02:38
  • @StilesCrisis: it's only a trap because the authors of some compilers failed to recognize that (as documented in the C99 Rationale), the authors of the Standard viewed the question of how to process many useful but non-portable constructs for which the Standard imposes no *requirements* as a "Quality of Implementation" issue *outside the Standard's jurisdiction*. They failed to recognize that a compiler that's freely distributable need not be very good to stomp others in the marketplace that would in every other way better fit their customers' needs. – supercat Feb 15 '20 at 23:22