Determining the Size of a Variable Using sizeof
Size is the amount of memory that the compiler reserves when the 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 usage of sizeof is simple. To determine the size of an integer, you invoke sizeof with parameter int (the type) as demonstrated by Listing 3.5.
cout << "Size of an int: " << sizeof (int);
LISTING 3.5 Finding the Size of Standard C++ Variable Types
1: #include <iostream> 2: 3: int main() 4: { 5: using namespace std; 6: cout << "Computing the size of some C++ inbuilt variable types" << endl; 7: 8: cout << "Size of bool: " << sizeof(bool) << endl; 9: cout << "Size of char: " << sizeof(char) << endl; 10: cout << "Size of unsigned short int: " << sizeof(unsigned short) << endl; 11: cout << "Size of short int: " << sizeof(short) << endl; 12: cout << "Size of unsigned long int: " << sizeof(unsigned long) << endl; 13: cout << "Size of long: " << sizeof(long) << endl; 14: cout << "Size of int: " << sizeof(int) << endl; 15: cout << "Size of unsigned long long: "<< sizeof(unsigned long long)<< endl; 16: cout << "Size of long long: " << sizeof(long long) << endl; 17: cout << "Size of unsigned int: " << sizeof(unsigned int) << endl; 18: cout << "Size of float: " << sizeof(float) << endl; 19: cout << "Size of 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 some C++ inbuilt variable types Size of bool: 1 Size of char: 1 Size of unsigned short int: 2 Size of short int: 2 Size of unsigned long int: 4 Size of long: 4 Size of int: 4 Size of unsigned long long: 8 Size of long long: 8 Size of unsigned int: 4 Size of float: 4 Size of 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 tells that the sizeof a variable doesn’t change between an unsigned or signed type; the only difference in the two is the MSB that carries sign information in the former.
Avoid Narrowing Conversion Errors by Using List Initialization
When you initialize a variable of a smaller integer type (say, short) using another 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, 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 avoid this problem, C++11 recommends list initialization techniques that prevent narrowing. To use this feature, insert initialization values/variables within braces {...}. The list initialization syntax is as follows:
int largeNum = 5000000; short anotherNum{ largeNum }; // error! Amend types int anotherNum{ largeNum }; // OK! float someFloat{ largeNum }; // error! An int may be narrowed float someFloat{ 5000000 }; // OK! 5000000 can be accomodated
It may not be immediately apparent, but this feature has the potential to spare bugs that occur when data stored in a type undergoes a narrowing conversion at execution time—these occur implicitly during an initialization and are tough to solve.