Home > database >  Why, in some C compilers, does `int x = 2147483647 1;` give only a warning but stores a negative v
Why, in some C compilers, does `int x = 2147483647 1;` give only a warning but stores a negative v

Time:06-13

I want to check if the reverse of an signed int value x lies inside INT_MAX and INT_MIN. For this, I have reversed x twice and checked if it is equal to the original x, if so then it lies inside INT_MAX and INT_MIN, else it does not.

But online compilers are giving a runtime error, but my g compiler is working fine and giving the correct output. Can anybody tell me the reason?

   int reverse(int x) {
        int tx=x,rx=0,ans;
        while(tx!=0){
            rx = rx rx rx rx rx rx rx rx rx rx tx;
            tx/=10;
        }
        
        ans = tx = rx;
        rx=0;
        
        while(tx!=0){
            rx = rx*10   tx;
            tx/=10;
        }
        
        while(x==0&&x!=0)x/=10;
        //triming trailing zeros
        
        if(rx!=x){
            return 0;
        }else{
            return ans;
        }
      
        
    }

ERROR:

Line 6: Char 23: runtime error: signed integer overflow: 1929264870   964632435 cannot be represented in type 'int' (solution.cpp)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:15:23

CodePudding user response:

According to the cppreference:

Overflows

... When signed integer arithmetic operation overflows (the result does not fit in the result type), the behavior is undefined: it may wrap around according to the rules of the representation (typically 2's complement), it may trap on some platforms or due to compiler options (e.g. -ftrapv in GCC and Clang), or may be completely optimized out by the compiler.

So the online compiler may comes with more strict checking, while your local GCC choosed to "wrap" on overflow.


Instead, if you want to wrap on overflow for sure, you may promote your operands to 64 bit width, perform the addition and then convert the result to 32 bit width again. According to cppreference this seems to be well defined after C 20.

Numeric conversions

Unlike the promotions, numeric conversions may change the values, with potential loss of precision.

Integral conversions

...

  • if the destination type is signed, the value does not change if the source integer can be represented in the destination type. Otherwise the result is { implementation-defined (until C 20) } / { the unique value of the destination type equal to the source value modulo 2n where n is the number of bits used to represent the destination type. (since C 20) }

Example code on godbolt

CodePudding user response:

I'm not sure what's wrong with your algorithm, but let me suggest an alternative that avoids doing math and the possibility of integer overflows.

If you want to find of if say, 2147483641 is a valid integer when reversed (e.g. 1463847412), you can do it entirely as string comparisons after converting the initial value to a string and reversing that string.

Basic algorithm for a non-negative value it this:

  • convert integer to string (let's call this string s)

  • convert INT_MAX to a string (let's call this string max_s)

  • reverse s. Handle leading zero's and negative chars appropriately. That is, 120 reversed is "21" and -456 reversed is "-654". The result of this conversion is a string called rev.

  • If rev.length() < s_max.length() Then rev is valid as an integer.

  • If rev.length() > s_max.length(), then rev is not valid as a integer.

  • If rev.size() == s_max.length(), then the reversed string is the same length as INT_MAX as a string. A lexical comparison will suffice to see if it's valid. That is isValid = (rev <= s_max) or isValid = strcmp(rev, s_max) < 1

The algorithm for a negative value is identical except replace INT_MAX with INT_MIN.

  • Related