4

I am trying to understand better how overflows behaves in C++. Consider the following MWE (must check for integer literals):

#include <cstdint>
#include <iostream>
#include <iomanip>

int main() {
    uint64_t known    = 6049417284;  // Known solution to operation.
    uint32_t option_1 = 77778u;      // Using 32 bits for operands.
    uint64_t option_2 = 77778ull;    // using 64 bits for operands.

    uint64_t sol_option_1 = option_1*option_1;
    uint64_t sol_option_2 = option_2*option_2;

    std::cout << std::boolalpha << (sol_option_1 == known) << std::endl;
    std::cout                   << (sol_option_2 == known) << std::endl;
}

Execution:

false
true

Why does it overflow with operands using 32 bits, even tough I explicitly request 64 bits to receive the solution?

My impression is that during run-time, C++ creates a temporary rvalue, whose precision is that from the operands, i.e. 32 bits. This overflows, and this result from an overflow is copied to the sol_option_1 variable, which receives the result from an overflow.

Eduardo
  • 697
  • 8
  • 26
  • 3
    `option_1 * option_1` is a calculation performed on 32-bit operands. The result is 32-bit. You then convert that 32-bit answer to be stored in a 64-bit variable, but the damage is already done. You would need to cast one of the operands to a 64-bit type **before** the multiplication (then the other would be converted automatically). – BoBTFish Oct 23 '18 at 06:29

2 Answers2

4

The answer is very simple: C++ doesn't care about what the result is being assigned to, it just takes the expression option_1 * option_1 and evaluates that. Then, it performs the assignment with the result. Note that you can also choose not to assign the result of an expression anywhere but that shouldn't affect the expression's evaluation.

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55
2

The first argument determines the type of the result.
In the first line, it is option1 (32 bit).
In the 2nd line, it is option2 (64 bit).

You can solve the overflow of the first line with:

uint64_t sol_option_1 = (uint64_t) option_1*option_1;
Tamir
  • 221
  • 2
  • 5