Department of Engineering

IT Services

C++ and simple type conversion

"Strongly typed" languages are fussy about mixing different types of variables. This is supposed to help reduce the number of programming errors at the expense of more verbose source code. C++ is one of the more strongly typed languages, but programmers still need to take responsibility for reducing type-related errors because there are many (too many, some think) implicit conversion rules that allow risky conversions. Compilers can detect these risky, "value-destroying", conversions but they're not often under an obligation to report them even if the resulting value is not defined in the language.

Here is a collection of small examples where types are mixed. Have a look at them, assess the level of risk, and try to guess how the compiler will react. I used gcc/g++ version 3.3.4 to test them, using the -Wall -ansi options.

  1. // chars and ints
    int main() {
    char c='A';
    int i=7;
    i=c;
    c=999;
    }
    
  2. // floats and doubles
    int main() {
    double d=9.9;
    float f=9.9;
    d=f;
    f=d;
    }
    
  3. // ints and doubles
    int main() {
    double d=9.9;
    int i;
    d=i;
    i=d;
    }
    
  4. // strings and chars
    #include <string>
    using namespace std;
    int main() {
    char c='A';
    string str;
    str=c;
    c=str;
    }
    
  5. // signed and unsigned ints
    int main() {
    int i=-9;
    unsigned int ui;
    ui=i;
    i=ui;
    }
    
  6. // ints and pointers
    int main() {
    int *pointer;
    pointer=0;
    pointer=4;
    }
    
  7. // const and non-const
    void fun(int& i) {
       ;
    }
    
    int main() {
    const int i;
    fun(i);
    }
    

Guess the answer!

See if you can guess what these programs will print. Compile and run the programs to see if you're right. Then try to explain the results.

  1. #include <iostream>
    int main() {
      unsigned int k=13;
      int j = 12;
      std::cout << "12 - 13=" << j - k << std::endl;;
    }
    
  2. #include <iostream>
    int main() {
      unsigned char k=13;
      char j = 12;
      std::cout << "12 - 13=" << j - k << std::endl;;
    }
    

Safety features

So, C++ doesn't fully protect you from type-conversion errors, but you can reduce the risks

  • Unsigned values - Don't assume that using unsigned values will give you any type-safe protection
  • Casting - The above examples mostly show simple types. Once you write your own classes, types can become complicated and conversions become correspondingly trickier. Read about Casting for more information about how to "cast" (convert) from one type to another. Note that in C there was a single casting method, a method also available in C++. The following, where 4 is cast into an int*, is legal but not recommended.
    int main() {
       int *pointer;
       pointer=(int*)4;
    }
    
    This type of casting can too easily lead to bugs. Use C++'s alternatives.
  • Limits - You can find out about numerical representation on your system by using <limits>. With the information it provides you can often check to see whether you risk "undefined behaviour". Here's an example showing how to determine limits
    #include <limits>
    #include <iostream>
    using namespace std;
    
    int main() {
      cout << "The maximum double value is " 
           << numeric_limits<double>::max() << endl;
    }