Assigning floating-point values to integer types poses a couple problems. First, converting floating-point to integer results in truncating the number (discarding the fractional part). Second, a float value might be too big to fit in a cramped int variable. In that case, C++ doesn’t define what the result should be; that means different implementations can respond differently.

Traditional initialization behaves the same as assignment. Listing 3.13 shows a few conversions by initialization.

Listing 3.13. init.cpp

// init.cpp -- type changes on initialization

#include

int main()

{

    using namespace std;

    cout.setf(ios_base::fixed, ios_base::floatfield);

    float tree = 3;     // int converted to float

    int guess(3.9832);  // double converted to int

    int debt = 7.2E12;  // result not defined in C++

    cout << "tree = " << tree << endl;

    cout << "guess = " << guess << endl;

    cout << "debt = " << debt << endl;

    return 0;

}

Here is the output from the program in Listing 3.13 for one system:

tree = 3.000000

guess = 3

debt = 1634811904

In this case, tree is assigned the floating-point value 3.0. Assigning 3.9832 to the int variable guess causes the value to be truncated to 3; C++ uses truncation (discarding the fractional part) and not rounding (finding the closest integer value) when converting floating-point types to integer types. Finally, note that the int variable debt is unable to hold the value 7.2E12. This creates a situation in which C++ doesn’t define the result. On this system, debt ends up with the value 1634811904, or about 1.6E09. Well, that’s a novel way to reduce massive indebtedness!

Some compilers issue warnings of possible data loss for those statements that initialize integer variables to floating-point values. Also the value displayed for debt varies from compiler to compiler. For example, running the same program from Listing 3.13 on a second system produced a value of 2147483647.

Initialization Conversions When {} Are Used (C++11)

C++11 calls an initialization that uses braces a list-initialization. That’s because this form can be used more generally to provide lists of values for more complicated data types. It’s more restrictive in type conversions than the forms used in Listing 13.3. In particular, list-initialization doesn’t permit narrowing, which is when the type of the variable may not be able to represent the assigned value. For example, conversions of floating types to integer types are not allowed. Converting from integer types to other integer types or floating types may be allowed if the compiler can tell if the target variable can hold the value correctly. For instance, it’s okay to initialize a long variable to an int value because long is always at least as big as int. Conversions in the other direction may be allowed if the value is a constant that can be handled by the type:

const int code = 66;

int x = 66;

char c1 {31325};  // narrowing, not allowed

char c2 = {66};   // allowed because char can hold 66

char c3 {code};   // ditto

char c4 = {x};    // not allowed, x is not constant

x = 31325;

char c5 = x;     // allowed by this form of initialization

For the initialization of c4, we know x has the value 66, but to the compiler, x is a variable and conceivably could have some other, much larger value. It’s not the compiler’s job to keep track of what may have happened to x between the time it was initialized and the time it was used in the attempted initialization of c4.

Conversions in Expressions

Consider what happens when you combine two different arithmetic types in one expression. C++ makes two kinds of automatic conversions in that case. First, some types are automatically converted whenever they occur. Second, some types are converted when they are combined with other types in an expression.

First, let’s examine the automatic conversions. When it evaluates expressions, C++ converts bool, char, unsigned char, signed char, and short values to int. In particular, true is promoted to 1 and false to 0. These conversions are termed integral promotions. For example, consider the following fowl statements:

short chickens = 20;           // line 1

short ducks = 35;              // line 2

short fowl = chickens + ducks; // line 3

To execute the statement on line 3, a C++ program takes the values of chickens and ducks and converts both to int. Then the program converts the result back to type short because the answer is assigned to a type short variable. You might find this a bit roundabout, but it does make sense. The int type is generally chosen to be the computer’s most natural type, which means the computer probably does calculations fastest for that type.

Перейти на страницу:

Все книги серии Developer's Library

Похожие книги