C++ Data Types
C++ programmers have access to the five data types for C: void, int, float, double, and char.
Type | Description |
---|---|
void | associated with no data type |
int | integer |
float | floating-point number |
double | double precision floating-point number |
char | character |
In addition, C++ defines two more: bool and wchar_t.
Type | Description |
---|---|
bool | Boolean value, true or false |
wchar_t | wide character |
Type Modifiers
Several of these types can be modified using the keywords signed, unsigned, short, and long. When one of these type modifiers is used by itself, a data type of int is assumed. A complete list of possible data types follows (equivalent types are displayed in the same row):
integer types | |||
---|---|---|---|
bool | |||
char | signed char | ||
unsigned char | |||
short | short int | signed short int | |
unsigned short | unsigned short int | ||
int | signed int | ||
unsigned | unsigned int | ||
long | long int | signed long | signed long int |
unsigned long | unsigned long int | ||
floating point types | |||
float | |||
double | |||
long double | |||
optionally supported integer types | |||
long long | signed long long | long long int | signed long long int |
unsigned long long | unsigned long long int | ||
wchar_t |
Type Sizes and Ranges
The size and range of any data type is compiler and architecture dependent. The “cfloat” (or “float.h”) header file often defines minimum and maximum values for the various data types. You can use the sizeof operator to determine the size of any data type (frequently expressed as a number of bytes). However, many architectures implement data types of a standard size. ints and floats are often 32-bit, chars 8-bit, and doubles are usually 64-bit. bools are often implemented as 8-bit data types. long long type is 64-bit.
Limits for numeric values are defined in the <limits> header. The templatized values of numeric_limits provide system-dependant numerical representations of the C++ data types. Use the appropriate function given the data type as the template argument as shown in the table below. Note that numeric_limits can be overloaded for user-defined types as well.
Method | Return | Description |
---|---|---|
is_specialized | bool | |
radix | int | base of exponent |
digits | int | number of radix digits in mantissa |
digits10 | int | number of base 10 digits in mantissa |
is_signed | bool | |
is_integer | bool | |
is_exact | bool | |
min | <type> | smallest number that can be respresented (not the most negative) |
max | <type> | largest number |
epsilon | <type> | inherent representation error value |
round_error | <type> | maximum rounding adjustment possible |
infinity | <type> | |
quiet_NaN | <type> | invalid number that does not signal floating point error |
signaling_NaN | <type> | invalid number that signals floating point error |
denorm_min | <type> | |
min_exponent | int | |
min_exponent10 | int | |
max_exponent | int | |
max_exponent10 | int | |
has_infinity | bool | |
has_quiet_NaN | bool | |
has_signaling_NaN | bool | |
has_denorm | <type>_denorm_style | |
has_denorm_loss | bool | |
is_iec559 | bool | conforms to IEC-559 |
is_bounded | bool | |
is_modulo | bool | |
traps | bool | |
tinyness_before | bool | |
round_style | float_round_style { round_to_nearest, … } |
The most common usage is in bounds checking, to determine the minimum and maximum values a data type can hold. The following code prints out the minimum and maximum values for a short on the system it is run.
#include <limits> std::cout << "Maximum short value: " << std::numeric_limits<short>::max() << std::endl; std::cout << "Minimum short value: " << std::numeric_limits<short>::min() << std::endl;
Reading Type Declarations
Simple type declarations are easy to understand:
int i
However, it can be tricky to parse a more complicated type declarations:
double **d[8] // hmm... char *(*(**foo [][8])())[] // augh! what is foo?
To understand the above declarations, follow three rules:
- Start at the variable name (
d
orfoo
in the examples above) - End with the data type (
double
orchar
above) - Go right when you can, and left when you must. (Grouping parentheses can cause you to bounce left.)
For example:
Expression | Meaning |
---|---|
double **d[8]; | |
| d is … double |
| d is an array of 8 … double |
| d is an array of 8 pointer to … double |
| d is an array of 8 pointer to pointer to double |
Another example:
Expression | Meaning |
---|---|
char *(*(**foo [][8])())[] | |
| foo is … char |
| foo is an array of … char |
| foo is an array of an array of 8 … char |
| foo is an array of an array of 8 pointer to … char |
| foo is an array of an array of 8 pointer to pointer to … char |
| foo is an array of an array of 8 pointer to pointer to function returning … char |
| foo is an array of an array of 8 pointer to pointer to function returning pointer to … char |
| foo is an array of an array of 8 pointer to pointer to function returning pointer to array of … char |
| foo is an array of an array of 8 pointer to pointer to function returning pointer to array of pointer to char |
For a much more detailed explanation, see Steve Friedl's excellent description of how to read C declarations at http://www.unixwiz.net/techtips/reading-cdecl.html.