Table of Contents

C++ Data Types

C++ programmers have access to the five data types for C: void, int, float, double, and char.

TypeDescription
voidassociated with no data type
intinteger
floatfloating-point number
doubledouble precision floating-point number
charcharacter

In addition, C++ defines two more: bool and wchar_t.

TypeDescription
boolBoolean value, true or false
wchar_twide 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
wchar_t
shortshort intsigned shortsigned short int
unsigned shortunsigned short int
intsignedsigned int
unsignedunsigned int
longlong intsigned longsigned long int
unsigned longunsigned long int
floating point types
float
double
long double
optionally supported integer types
long longlong long intsigned long longsigned long long int
unsigned long longunsigned long long int

Type Sizes and Ranges

The size and range of any data type is compiler and architecture dependent. 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. The “cfloat” (or “float.h”) header file defines the ranges for the floating types, the “climits” (or “limits.h”) - for the integer types.

Limits for numeric values are defined in the <limits> header. The templated 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 or
constant
ReturnDescription
is_specializedbool
radixintbase of exponent
digitsintnumber of radix digits in mantissa
digits10intnumber of base 10 digits in mantissa
is_signedbool
is_integerbool
is_exactbool
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_exponentint
min_exponent10int
max_exponentint
max_exponent10int
has_infinitybool
has_quiet_NaNbool
has_signaling_NaNbool
has_denorm<type>_denorm_style
has_denorm_lossbool
is_iec559boolconforms to IEC-559
is_boundedbool
is_modulobool
trapsbool
tinyness_beforebool
round_stylefloat_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 more complicated type declarations:

  double **d[8]              // hmm...
  char *(*(**foo [][8])())[] // augh! what is foo?

To understand the above declarations, follow three rules:

  1. Start at the variable name (d or foo in the examples above)
  2. End with the data type (double or char above)
  3. Go right when you can, and left when you must. (Grouping parentheses can cause you to bounce left.)

For example:

ExpressionMeaning
double **d[8];
double **d[8]; d is … double
double **d[8]; d is an array of 8 … double
double **d[8]; d is an array of 8 pointer to … double
double **d[8]; d is an array of 8 pointer to pointer to double

Another example:

ExpressionMeaning
char *(*(**foo [][8])())[]
char *(*(**foo [][8])())[] foo is … char
char *(*(**foo [][8])())[] foo is an array of … char
char *(*(**foo [][8])())[] foo is an array of an array of 8 … char
char *(*(**foo [][8])())[] foo is an array of an array of 8 pointer to … char
char *(*(**foo [][8])())[] foo is an array of an array of 8 pointer to pointer to … char
char *(*(**foo [][8])())[] foo is an array of an array of 8 pointer to pointer to function returning … char
char *(*(**foo [][8])())[] foo is an array of an array of 8 pointer to pointer to function returning pointer to … char
char *(*(**foo [][8])())[] foo is an array of an array of 8 pointer to pointer to function returning pointer to array of … char
char *(*(**foo [][8])())[] 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.