Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

subtraction between unsigned values - unexpected result

Tags:

c++

c

I have two variables (test1 and test2), both unsigned. I need to check which of them is bigger.

I'm trying to understand what happens if overflow occurs.

My first test was done with uint8_t (char) data type:

#include <stdio.h>
#include <stdint.h>
#include <math.h>

int main()
{
    uint8_t test1 = 0;
    printf("test1 = %d\n", test1);

    uint8_t test2 = pow(2, 8 * sizeof(test1)) - 1; //max holdable value of uint8_t
    printf("test2 = %d\n", test2);

    uint8_t test3 = test1 - test2;
    printf("test1 - test2 = %d\n", test3);

    if ((test1 - test2) == 0)
        printf("test1 == test2\n");
    if ((test1 - test2) > 0)
        printf("test1 > test2\n");
    if ((test1 - test2) < 0)
        printf("test1 < test2\n");

    if (test3 == 0)
        printf("test1 == test2\n");
    if (test3 > 0)
        printf("test1 > test2\n");
    if (test3 < 0)
        printf("test1 < test2\n");

    return 0;
}

output:

test1 = 0                                                                                                                                                       
test2 = 255                                                                                                                                                     
test1 - test2 = 1                                                                                                                                               
test1 < test2                                                                                                                                                   
test1 > test2

What? Making the substraction and save it in a variable, then checking it, is different from checking the substraction on the fly?

My second test was done with uint32_t (long) data type:

#include <stdio.h>
#include <stdint.h>
#include <math.h>

int main()
{
    uint32_t test1 = 0;
    printf("test1 = %d\n", test1);

    uint32_t test2 = pow(2, 8 * sizeof(test1)) - 1; //max holdable value of uint32_t
    printf("test2 = %lu\n", test2);

    uint32_t test3 = test1 - test2;
    printf("test1 - test2 = %d\n", test3);

    if ((test1 - test2) == 0)
        printf("test1 == test2\n");
    if ((test1 - test2) > 0)
        printf("test1 > test2\n");
    if ((test1 - test2) < 0)
        printf("test1 < test2\n");

    if (test3 == 0)
        printf("test1 == test2\n");
    if (test3 > 0)
        printf("test1 > test2\n");
    if (test3 < 0)
        printf("test1 < test2\n");

    return 0;
}

output:

test1 = 0                                                                                                                                                       
test2 = 4294967295                                                                                                                                              
test1 - test2 = 1                                                                                                                                               
test1 > test2                                                                                                                                                   
test1 > test2

What??? Now making the substraction and saving it in a variable, then check it, is the same as checking the substraction on the fly?

SO I was expecting that substraction between unsigned values (without an explicit cast) ALWAYS returns a value >= 0. But doing the substraction inside the IF leads to unexpected results.

Now I'm confused. Can someone explain this behaviour to me?

like image 623
Suxsem Avatar asked Dec 21 '15 08:12

Suxsem


1 Answers

The somewhat arcane type promotion rules apply. In the first example where the operands are uint8_t, for the expression:

test1 - test2

both operands are implicitly promoted to int before subtraction, and the expression itself has type int.

like image 189
Clifford Avatar answered Sep 18 '22 05:09

Clifford