-1

Say I want to print some values. I am assuming that I should get Integer Overflow if my signed variable exceeds from TMin and TMax (in this case, using 4 byte int, 0x7FFFFFFF as Tmax and 0x80000000 as Tmin) but in these example I am not getting what I expect (explained in comments):

// Tmax = 0x7FFFFFFF == 2147483647 
// Tmin = 0x80000000 == -2147483648 
printf("1- overflow test: %d\n", 0x7FFFFFFF+1 ); // overflow - how compiler finds out it's a signed value, not an Unsigned one
printf("2- overflow test: %d\n", 0x80000000-1 ); // in contrast, why I am not getting an integer overflow here
printf("3- overflow test: %d\n", (int) 0x80000000-1 ); // overflow (Expected)
printf("4- overflow test: %d\n",(int) (0x7FFFFFFF+1)); // overflow (Expected)
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
Yar
  • 7,020
  • 11
  • 49
  • 69

4 Answers4

2

First of all, let me tell you, (signed) integer overflow invokes undefined behavior.

In that scenario, anything can happen. You can neither trust nor reasonify the output of a code having UB.

Just to clarify, even

printf("2- overflow test: %d\n", 0x80000000-1 );

is UB. Though 0x80000000-1 is unsigned and not an overflow in itself, using %d will lead to a type mismatch which will technically lead to UB.

Regarding the Undefined behavior, from C11, annex §J.2,

Conversion to or from an integer type produces a value outside the range that can be represented.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • What about signed `long` `signed `char`? etc.? (Sorry for being nit-picky. Just think more general ;-) – too honest for this site Feb 01 '16 at 20:14
  • @Olaf is changing that to "signed integer types" makes it better? – Sourav Ghosh Feb 01 '16 at 20:20
  • @Olaf I'm referring to §6.2.5/17. Will that be ok? :) – Sourav Ghosh Feb 01 '16 at 20:23
  • Why not just cite (and link) the standard. See 3.4.3 for instance. Whats wrong with just "signed integer"? ;-) – too honest for this site Feb 01 '16 at 20:24
  • @Olaf Updated now. Please review once. – Sourav Ghosh Feb 01 '16 at 20:32
  • "... lead to a type mismatch which will technically lead to UB." is not so as there is an exception in C - now to find it. C11 §6.5.2.2 6. Since the value is representable in both `int` and `unsigned`, no UB. – chux - Reinstate Monica Feb 01 '16 at 20:34
  • @chux Sorry, I did not get your point. `%d` with unsigned >> _"If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined."_ or am I missing something here? – Sourav Ghosh Feb 01 '16 at 20:37
  • Read carefully C11 §6.5.2.2 6 "...one promoted type is a signed integer type, the other promoted type is the corresponding unsigned integer type, and the value is representable in both types". As I read it, it means that is an `int/unsigned` is expected yet a `unsigned/int` is given in a `f(...)` and the value is representable in both types, like `0x7FFFFFFF`, then there is no UB. – chux - Reinstate Monica Feb 01 '16 at 20:46
  • @chux Confused!! Isn't that about the missing prototype? Is that applicable for variadic functions? Just the case before that, the varidic notation is mentioned explicitly. However, let me read through it again, carefully. – Sourav Ghosh Feb 01 '16 at 20:53
1

Trying to invoke integer overflow is undefined behavior. As per standard, in that case anything, including outwardly appearing non-overflow can happen. What this outputs is uninteresting and irrelevant.

It may be that your compiler optimizes it out. It may be that your system refuses to be used in such a way, it may be that a sack of rice falling in china caused a butterfly effect that lead to this. Its anything but defined what happens there.

It may also be that your system decided that its integers are bigger. Only the lower limit of integer sizes (2 byte) is mandated in c (at least 4 is typical for standard computers). Your system could have 8 byte integers, or even bigger ones.

Magisch
  • 7,312
  • 9
  • 36
  • 52
  • so if int overflow happens pretty much randomly, how we can determine if say a random input would get an overflow or not? – Yar Feb 01 '16 at 20:11
  • @HoomanYar By ensuring your value goes not above whats permitted in your integer. Overflow only happens when you go above that. So if your int is 32 bit (which it most likely is), just dont do over 2^32 -1 in value or not over 2^32 / 2 - 1 for signed integers, and not below - 2^32 for signed integers – Magisch Feb 01 '16 at 20:13
  • *"Only the lower limit of integer sizes (4 byte) is mandated in c."* - 2 bytes, surely? – Weather Vane Feb 01 '16 at 20:13
  • @HoomanYar: Nothing happens randomly unless you have some source of true white noise in your system. Please carefully think about the meaning of **undefined**, like in _undefined behaviour_. Prepare for nasal daemons, your computer commiting suicide by jumping out of the window, etc. – too honest for this site Feb 01 '16 at 20:13
  • @WeatherVane In modern systems for simplicity. But feel free to edit the caveat in. – Magisch Feb 01 '16 at 20:14
  • @WeatherVane changed it. – Magisch Feb 01 '16 at 20:16
  • 1
    @Magisch: Most systems sold have 16 bit `int`. And the standard allows for padding bits. – too honest for this site Feb 01 '16 at 20:16
1

OP is not always experiencing signed integer overflow - which is undefined behavior.

The following is unsigned math as 0x80000000 is likely an unsigned integer. Hexadecimal constants are of the type that first fits them int, unsigned, long, unsigned long, ...

printf("2- overflow test: %d\n", 0x80000000-1 );

0x80000000-1 is an unsigned type as 0x80000000 first fits in an unsigned type, likely unsigned with the value of 2147483648u. 2147483648u - 1 --> 2147483647u.

0x7FFFFFFF+1 is a signed type as 0x7FFFFFFF first fits in a signed type, likely int with the value of INT_MAX.
int + int --> int and INT_MAX + 1 --> overflow.


OP said "0x80000000 as Tmin" is certainly a mis-understanding. In C, with 32-bit int/unsigned, 0x80000000 is a hexadecimal constant with the value of 2147483648. For OP, Tmin is more likely -INT_MAX - 1.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Once you invoke UB, all bets are off, no matter if the rest is ok. IOW: UB is virulent. – too honest for this site Feb 01 '16 at 20:28
  • @Olaf OP's code comments "why I am not getting an integer overflow here" is certainly discovered from a lack of a compile time warning. The reason is discussed in this answer. Of course UB is a run-time issue. – chux - Reinstate Monica Feb 01 '16 at 20:32
  • Ok, got your point. My comment was mostly that after the first overflow, all bets are off for the following code. – too honest for this site Feb 01 '16 at 20:37
  • @Oalf I think it is even worse than that. Some compilers take advantage if in _later_ code, UB will certainly occur, they perform some interesting optimizations on prior code - like not even executing it! I followed some interesting debates on this issue about the legitimacy of that. Moral of the story: UB is UB is UB. – chux - Reinstate Monica Feb 01 '16 at 20:42
  • I completely agree with that standpoint. It is full in-line with allowing the compiler to rearrange code internally, as long as the _observable behaviour_ is correct. As you might have notice I don't tend to be very tolerant to failures. (Things are different if a system has to tolerate failures ...:-) – too honest for this site Feb 01 '16 at 20:54
  • See @SouravGhosh's answer. While `0x80000000 - 1` is not UB, using `%d` actually. is. – too honest for this site Feb 01 '16 at 20:57
  • @Oalf Consider [C11 §6.5.2.2 6](http://stackoverflow.com/questions/35139204/not-getting-integer-overflow/35139463?noredirect=1#comment58000288_35139254). I suspect it will take an SO post to clear that up. – chux - Reinstate Monica Feb 01 '16 at 21:21
1

C is kind of inconsistent about numeric exceptions.

There are a few things you can do that almost always cause problems. If you divide by 0, your program will usually crash pretty hard, just as if you'd accessed an invalid pointer.

There are a few things you can do that are guaranteed not to cause a problem. If you say

unsigned int i = UINT_MAX;

and then add 1 to it, it's guaranteed to wrap around to 0.

And then there are a number of things where the behavior is undefined or unspecified. Signed integer overflow is one of these. Strictly speaking it's undefined (anything can happen, you can't depend on it). In practice, most computers quietly wrap around, just like for unsigned arithmetic.

Now, everything I've said has been about the run-time behavior of a program, but in this question's posted code fragment, all the arithmetic happens at compile time. Compile-time arithmetic operates mostly according to the same rules as run-time, but not always. Modern compilers tend to warn you about problematic compile-time arithmetic (my copy of gcc emits three warnings for the posted fragment), but not always.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103