Integer division overflows

后端 未结 2 1694
慢半拍i
慢半拍i 2020-12-31 08:55

The Problem

I have been thinking about integer (type int) overflows, and it occurs to me that division could overflow.

Example: On my curr

相关标签:
2条回答
  • 2020-12-31 09:19

    What guarantees (in C or C++ standard) might help to devise the code?

    C specifies signed integer representation as using 1 of 3 forms: sign and magnitude, two’s complement, or ones’ complement. Given these forms, only division by 0 and two’s complement division of INT_MIN/-1 may overflow.

    What (cross-platform) C code could one write in order to prevent division overflows (for type (signed) int)?

    int safe_int_div(int * res, int op1, int op2) {
      if (op2 == 0) {
        return 1;
      }
      // 2's complement detection
      #if (INT_MIN != -INT_MAX) 
        if (op1 == INT_MIN && op2 == -1)  {
          return 1;
        }
      #endif
      *res = op1 / op2;
      return 0;
    }
    
    0 讨论(0)
  • 2020-12-31 09:37

    1) Just as for any other operation in C, the application has to ensure that:

    • the type used for the calculation itself is large enough, and
    • the type of the variable where the result is stored is large enough.

    The way to ensure this is to set size limits of each operand before the operation. What limits that are suitable depends on the algorithm and the purpose of the variables.

    2) If you use stdint.h of the C standard, you get guarantees of how big the variables are, portably. You should never use int when writing portable code.

    As for the case of writing a safe division routine, it would take 32 bit integers as parameters, then perform the calculation on 64 bit integers and return the result as a 32 bit integer.

    #include <stdint.h>
    #include <stdbool.h>
    
    /*
          Try to divide integer op1 by op2.
          Return
            true (success) or
            false (possibly overflow prevented).
          In case of success, write the quotient to res.
          In case of failure, res remains untouched.
    */
    
    bool safe_int_div (int32_t* res, int32_t op1, int32_t op2) {
    
      if(op2 == 0)
        return false;
    
      int64_t res64 = (int64_t)op1 / (int64_t)op2;
    
      if(res64 > INT32_MAX || res64 < INT32_MIN)
        return false;
    
      *res = (int32_t)res64_t;
    
      return true;
    }
    

    If further information of why the division failed is desired, replace the bool with an enum.

    0 讨论(0)
提交回复
热议问题