c and cpp pitfalls, mixing signed and unsigned integer, implicit conversion

copyright (C) qingfeng Xia 2011-2020 CC-BY-NC 4.0

1. mixing unsigned and sign int is a bad idea

  • first of all, remember: signed int types will be implicitly converted to unsigned if sizeof(signed int types) == sizeof(unsigned int types)
  • Google C++ coding standard, say “do not use unsigned integer”
  • C++ STL using size_t which is unsigned int to represent size of containters like std::vector, std::string
  • do not assume sizeof(int types), always #include <stdint.h> and use int64_t
  • compiler can warn warning: comparison between signed and unsigned integer expressions [-Wsign-compare] . However, mixed unsigned and signed int algorithm is not warned
  • JAVA before Java 8 SE does not support unsigned int, even in Java 8 SE you can not declare unsigned int types, but only using static methods, unsigned comparison.
    There are good reason not to supported it.
  • python built-in integer/long is unsigned, but ctypes module defined c++ unsigned types; python 3 integer will not overflow
  • see also

http://blog.robertelder.org/signed-or-unsigned-part-2/

example and explanation from stackoverflow

2. Relevant quote from the Standard: Expressions

10 Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are de?ned as follows:

2 clauses about equal types or types of equal sign omitted

  • Otherwise, if the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type shall be converted to the type of the operand with unsigned integer type.
  • Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, the operand with unsigned integer type shall be converted to the type of the operand with signed integer type.
  • Otherwise, both operands shall be converted to the unsigned integer type corresponding to the type of the operand with signed integer type.

3. pitfall of overflow and underflow

  • overflow detection can not been done by compiler but user
  • float overflow could be captured and hook to abort routine
  • avoiding infinite looping for underflow by compiler warning

    comparison of unsigned expression >= 0 is always true [-Wtype-limits]

  • assigned minus int to unsigned int should be prohibited, try hex instead or UINT_MAX – 1, since compiler will not warn you for implicit conversion into unsigned int types

4. pitfall of implicit conversion

see more c and c++ pitfalls

Guru of the Week (GotW)

Guru of the Week (GotW) is a series of C++ programming problems created and written by Herb Sutter.

#include <iostream>
#include <limits>
#include <vector>


void std_container_test(){
    std::vector<int> v;
    int i = 10;
    if (i < v.size()-1) // there is a compiler warning here
        std::cout <<"underflow occurs for empty container size()-1\n";
}

void underflow_test(int input_s, unsigned int input_u){
	unsigned int size_u = 10u;
	unsigned int i_u;
	int size_s = 10;
	int i_s;
    // infinite looping for underflow
	for(i_u = size_u -1; i_u >=0; i_u--){
		std::cout <<"unsigned: " << ((input_u + i_u) / 2u) << "\n";
	}
}

void float_overflow_test() {

    float d = std::numeric_limits<float>::max();
    std::cout << "std::numeric_limits<float>::max() = " << d << std::endl;
    float q = d + 100;  //behavior is undefined,  could be inf, or remained as std::numeric_limits<float>::max() 
    std::cout << "q: " << q << std::endl;

}

void bool_implicit_coversion_pitfall_test() {
    int x = 0;
    if (!(-0.5 <= x <= 0.5))
        std::cout << "x=0, -0.5 <= x <= 0.5 is false"<<"\n";
}

void signed_int_test() {

    signed int s1 = -4;
    unsigned int u1 = 2;

    signed long long s2 = -4;
    unsigned int u2 = 2;

    signed long long int s3 = -4;
    unsigned long int u3 = 2;

    unsigned long int u4 = -2; // no worning at all

    if (s1>u1)
        std::cout << s1 << " > " << u1 << " is true? \n";
    std::cout << (s1 + u1) << "\n"; // 4294967294
    std::cout << (s2 + u2) << "\n"; // -2 
    std::cout << (s3 + u3) << "\n"; // 18446744073709551614 
    
    std::cout << " What are you expecting from `unsigned long int u4 = -2;`, actually stored integer is " << u4<< "\n"; 
}

int main()
{
    signed_int_test();
    bool_implicit_coversion_pitfall_test() ;
    std_container_test();
    float_overflow_test();
}

 



CC-BY-NC 4.0 licensed free for non-commercial usage
Author: Qingfeng XIA
copyright (C) 2011-2020
http://www.iesensor.com
please keep the original link in your reference.
http://www.iesensor.com/blog/2016/12/21/c-and-cpp-pitfalls-mixing-signed-and-unsigned-integer-implicit-conversion/
This entry was posted in Programming. Bookmark the permalink.