- What Is a Variable?
- Common Compiler-Supported C++ Variable Types
- Determining the Size of a Variable by Using sizeof()
- Automatic Type Inference Using auto
- Using typedef to Substitute a Variable’s Type
- What Is a Constant?
- Keywords You Cannot Use as Variable or Constant Names
- Summary
- Q&A
- Workshop
Determining the Size of a Variable by Using sizeof()
Size is the amount of memory that the compiler reserves when a programmer declares a variable to hold the data assigned to it. The size of a variable depends on its type, and C++ has a very convenient operator called sizeof() that tells you the size, in bytes, of a variable or a type.
The use of sizeof() is simple. To determine the size of an integer, you invoke sizeof() with parameter int (the type), as shown here and further demonstrated in Listing 3.5:
cout << "Size of an int: " << sizeof (int);
Input ▼
Listing 3.5 Finding the Sizes of Standard C++ Variable Types
1: #include<iostream> 2: 3: int main() 4: { 5: using namespace std; 6: cout << "Computing the size of inbuilt variable types" << endl; 7: 8: cout << "sizeof bool: " << sizeof(bool) << endl; 9: cout << "sizeof char: " << sizeof(char) << endl; 10: cout << "sizeof unsigned short int: " << sizeof(unsigned short) << endl; 11: cout << "sizeof short int: " << sizeof(short) << endl; 12: cout << "sizeof unsigned long int: " << sizeof(unsigned long) << endl; 13: cout << "sizeof long: " << sizeof(long) << endl; 14: cout << "sizeof int: " << sizeof(int) << endl; 15: cout << "sizeof uns. long long: "<< sizeof(unsigned long long)<< endl; 16: cout << "sizeof long long: " << sizeof(long long) << endl; 17: cout << "sizeof unsigned int: " << sizeof(unsigned int) << endl; 18: cout << "sizeof float: " << sizeof(float) << endl; 19: cout << "sizeof double: " << sizeof(double) << endl; 20: 21: cout << "The output changes with compiler, hardware and OS" << endl; 22: 23: return 0; 24: }
Output ▼
Computing the size of inbuilt variable types sizeof bool: 1 sizeof char: 1 sizeof unsigned short int: 2 sizeof short int: 2 sizeof unsigned long int: 4 sizeof long: 4 sizeof int: 4 sizeof uns. long long: 8 sizeof long long: 8 sizeof unsigned int: 4 sizeof float: 4 sizeof double: 8 The output changes with compiler, hardware and OS
Analysis ▼
The output of Listing 3.5 reveals sizes of various types, in bytes, and is specific to my platform: compiler, OS, and hardware. This output in particular is a result of running the program in 32-bit mode (compiled by a 32-bit compiler) on a 64-bit operating system. Note that a 64-bit compiler probably creates different results, and the reason I chose a 32-bit compiler was to be able to run the application on 32-bit as well as 64-bit systems. The output indicates that the size of a variable doesn’t change between unsigned and signed types; the only difference in the two is the MSB, which carries sign information in signed types.
Avoid Narrowing Conversion Errors by Using List Initialization
When you initialize a variable of a smaller integer type (say, short) by using another variable of a larger type (say, an int), you are risking a narrowing conversion error because the compiler has to fit data stored in a type that can potentially hold much larger numbers into a type that doesn’t have the same capacity (that is, it is narrower). Here’s an example:
int largeNum = 5000000; short smallNum = largeNum; // compiles OK, yet narrowing error
Narrowing isn’t restricted to conversions between integer types only. You may face narrowing errors if you initialize a float using a double, a float (or double) using an int, or an int using a float. Some compilers may warn, but this warning will not cause an error that stops compilation. In such cases, you may be confronted by bugs that occur infrequently and at execution time.
To prevent errors due to narrowing, use list initialization techniques and insert initialization values/variables within braces {...}. List initialization works as follows:
int largeNum = 5000000; short anotherNum{ largeNum }; // error! Amend types int anotherNum{ largeNum }; // OK! float someFloat{ largeNum }; // error! Type int being narrowed float someFloat{ 5000000 }; // OK! 5000000 can be accommodated
It might not be immediately apparent, but this feature has the potential to prevent bugs that occur when data stored in a type undergoes a narrowing conversion at execution time. These bugs occur implicitly during an initialization and are tough to solve.