0

Can someone please explain why the following code results in total of 0? How does that add up to zero? I get the same result using different types such as long and long long. Thank you!

int num;
num = (256 * 256 * 256 * 256)-1;    //-1 warning C4307: '*': integral constant overflow
cout << num << endl;

num = 256 * 256 * 256 * 256;    //0 warning C4307: '*': integral constant overflow
cout << num << endl;            

num = (256 * 256) * (256 * 256);     //0 warning C4307: '*': integral constant overflow
cout << num << endl;


num = (256 * (256 * 256) * 256);     //0 warning C4307: '*': integral constant overflow
cout << num << endl;             

num = 256 * 256 * 256; // 16777216
cout << num << endl;

num = 256 * 256;    //65536
cout << num << endl;

output:
-1
0
0
0
16777216
65536

Changing the type only affects: num = 256 * 256; num = num * 256 * 256; which adds up correctly.

long long num;
num = (256L * 256L * 256L * 256L)-1;        //warning C4307: '*': integral constant overflow
cout << num << endl;

num = (256L * 256L * 256L * 256L);      //warning C4307: '*': integral constant overflow
cout << num << endl;            

num = (256 * 256) * (256 * 256);     //warning C4307: '*': integral constant overflow
cout << num << endl;


num = (256 * (256 * 256) * 256);     //warning C4307: '*': integral constant overflow
cout << num << endl;             

num = 256 * 256 * 256;
cout << num << endl;

num = 256 * 256;
cout << num << endl;
num = num * 256 * 256;
cout << num << endl;

cout << sizeof(int) << endl;
cout << sizeof(long long) << endl;

output:
-1
0
0
0
16777216
65536
4294967296
sizeof(int) 4
sizeof(long long) 8

I suppose it has to do with the number of '*' multiplication operators. The math works with 3 or less.

4 Answers4

3

Why warning C4307: '*': integral constant overflow ?

The literal 256 has a default size of 4 bytes and the result of arithmetic operations involving 4 byte integers will be allocated 4 bytes. So:

256 in hex notation is 0x100
256 * 256 * 256 * 256
= 0x100 * 0x100 * 0x100 * 0x100
= 0x 01 00 00 00 00  //Too big for 4 bytes, therefore overflow

Why 256 * 256 * 256 * 256 == 0?

Continuing from above.

//The result of the calculation is **mashed** into 4 bytes
0x 01 00 00 00 00
      ^^^^^^^^^^^
//The last 4 bytes == 0 and this is the value assigned to num

Even if num is declared as an 8 byte integer (long long) at this point:

  • 0 is the result (in 4 bytes).
  • and 0 will assigned to num.

Solution

Declare your literals as 8 byte values (i.e. 256LL) and the result of the calculation should also be 8 bytes.

long long num = 256LL * 256LL * 256LL * 256LL;

NOTE: The size limits of primitive types is a standard issue in software development. If you use 8 byte integers, you're still limited to the maximum possible 8 byte value which is 264-1. Read the section on Integer type here for more information.

If you need arbitrarily large numbers, you need to use a library that provides such functionality.

Community
  • 1
  • 1
Disillusioned
  • 14,635
  • 3
  • 43
  • 77
  • Further reading: http://en.cppreference.com/w/cpp/language/integer_literal (Note also that C++ specifies _minimum_ sizes for various types. So the sizes can vary by compiler/version.) – Disillusioned Jun 15 '17 at 06:31
2

Even if the target variable is long long, all parts of the expression are (32-bit) int. And no matter how you try to group the multiplications, the result is 2**32, whose low 32 bits are 0.

Mischa
  • 2,240
  • 20
  • 18
2

256 = 28, and

256 * 256 * 256 * 256

= 28 * 28 * 28 * 28

= 2(8 + 8 + 8 + 8)

= 232

Whereas (going by your error), your machine supports ints within the range -231 to 231 - 1 only.

So 232 causes an overflow resulting in 0, because all bits except the MSB are 0.

cs95
  • 379,657
  • 97
  • 704
  • 746
2

Our number system (that we write) stores number in decimal (base 10) where each digit can take on the 10 different values (0-9). If you had a calculator with only 6 digits, the largest number you could display is 999999. If you tried multiplying 1000 * 1000 you would either get an error or the calculator would have to get rid of the digits above the 6th or both.

A computer stores number in binary (base 2). C (and C++) defines several data types that define how a number will be stored. Microsoft C++ (VCPP) further clarifies these. For a signed integer number these are:

  • short (min 16 bits) MSVCPP=16bit
  • int (min 16 bits) MSVCPP=32bit
  • long (min 32 bits) MSVCPP=32bit
  • long long (min 64 bits) MSVCPP=64bit

    Note the word 'usually' since the C standard sets a minimum size but not a max

    Also Note: I know I skipped char because (IMHO) it is a bit of a hybrid type.

There are also unsigned types that trade an sign bit for an extra numeric so they can store larger (positive) numbers.

Ok, so back to your question. As @Coldspeed mentioned 256=28. In binary, that requires 10 bits to represent as a signed number and 9 bits as an unsigned. That will easily fit into any of these types. When you get to 256 * 256 * 256 * 256 = 232, that would require a 34 bits which only fits into a long long. Just like on the 6-digit calculator, you will either get an error of loose the upper digit(s) or both. In this case loosing the upper digit(s) will result in '0'.

This explains your first four answers (for the first, think that 0-1 = -1)

But why doesn't long long work. Well the answer is that that is ONLY where the final result is stored. Unless you specify otherwise, all integer literals (numbers) will be treated as of int type; so, the truncation/error happens during the calculation int the calculation before the number is placed into num.

The last two are ambiguous in 'C' because they could result in an error since the result is larger than a short can hold and an int is not guaranteed to be bigger than a short; but, for MSVCPP it is (32bit).

markshancock
  • 690
  • 2
  • 7
  • 25
  • Thank you! Wonderful explanation. – Eric Lieber Jun 15 '17 at 07:11
  • A well written piece! – cs95 Jun 15 '17 at 09:44
  • "get an error or lose the upper digits" - signed integer overflow in C++ is Undefined Behaviour. In source that runs this statement, the compiler is "allowed" to break anything and everything, in interesting ways, if it so desires. Yes in practice you'll usually get truncation (and a compiler warning if it happens during compile-time evaluation), but it's important to at least mention the concept of undefined behaviour. – Peter Cordes Feb 25 '21 at 08:55
  • *all integer literals (numbers) will be treated as of int type;* not quite true: the type of a literal is int, or the smallest type that can hold the value if larger than int. e.g. `4294967296` has type `long long`. – Peter Cordes Feb 25 '21 at 08:58