Fundamental types in C++ are comprised of the type `void`

`nullptr`

and the *Arithmetic Types* listed in the below table.

Fundamental types are also called basic types, primitive types, built-in types, intrinsic types

Category | Type | Min Size | Description | |
---|---|---|---|---|

void | `void` Functions are functions that don’t return any value. `void` Pointers has no set type, it can point to any data type. Must be dereferenced explicitly before usage. There are no `void` objects, arrays, references to `void` . |
|||

std::nullptr_t | A distinct type (not a pointer) representing a null pointer. `typedef` ed as `nullptr` in `<cstddef>` . Introduced in C++11 |
|||

Integral | ||||

bool | * | A type that can hold the values `true` and `false` . When converting to/from integrals 0 means `false` any other numeric value means `true` including negative values. *Implementation defined, usually 1 byte |
||

char | 1 byte | An 8-bit integral value that is used to represent ASCII character set. Range is 0…255 or -127…128, so the signedness is implementation defined. `signed char` and `unsigned char` are other distinct types that can be used where it matters. Since C++14, this type is large enough to represent UTF-8 code unit. |
||

wchar_t | 2 | 4 bytes see description |
An integral value that is used to represent wide characters. 32 bits in systems that support Unicode. Windows specific: 16 bits and holds UTF-16 code units. | |

char16_t | 2 bytes | An 16-bit integral value that is used to hold UTF-16 code units. | ||

char32_t | 4 bytes | An 32-bit integral value that is used to hold UTF-32 code units. | ||

int | 4 bytes | A 32-bit integral type that can hold integer values between -2,147,483,648…2,147,483,647 or up to 4,294,967,295 when unsigned. | ||

Floating Point | ||||

float | 4 bytes | Single precision floating point number. 6 significant digits | ||

double | 8 bytes | Double precision floating point number. 10 significant digits | ||

long double | 8 bytes | Extended double precision floating point number. 10 significant digits. It’s typically 12 or 16 bytes (triple or quadruple precision) based on implementation. |

**Figure 1.1.** Table of fundamental types in C++.

To check the size in bytes for your compiler, use the `sizeof`

operator (e.g. `std::cout << sizeof(int) << std::endl;`

)

Size | Signedness | ||
---|---|---|---|

`short` or `short int` |
Use at least 2 bytes 2 ^{16} values, [–32,768..32,767] |
`signed` |
Signed range/representation (default) |

`long` or `long int` |
Use at least 4 bytes 2 ^{32} values, [~–2.1 billion..~2.1 billion] |
`unsigned` |
Unsigned range/representation |

`long long` or `long long int` |
Use at least 8 bytes 2 ^{64} values, [~–9.2 quintillion..~9.2 quintillion] |

**Figure 1.2.** Table of integer type modifiers.

All integral types are signed by default.

Floating point types don’t have `unsigned`

versions.

Any value assignable to a built-in variable is a literal.

Literals have types.

`5`

is an integer literal,`5.5`

is a double literal.`'a'`

is a char literal.`"Test"`

is a string literal (a null terminated constant char array).Some literals take prefix and suffixes specifying the type.

Suffix/Prefix | Usage | Description |
---|---|---|

F or f | `5.5f` |
float |

L or l | `500L` `500.0L` `L"Test"` |
long int long double wchar_t |

LL or ll | `500LL` |
long long int |

u8 | `u8"Test"` |
UTF-8 char, applicable to strings only |

u | `u"Test"` `50u` |
char16_t unsigned int |

U | `U"Test"` `50U` |
char32_t unsigned int |

0 | `050` |
Octal representation |

0x | `0x50` |
Hexadecimal representation |

**Figure 1.3.** Table of literal prefixes and suffixes.

Some of the the prefixes can be mixed for a desired outcome. e.g. `500ULL`

is `unsigned long long`

Technically there are no negative decimal literals. The

`-`

sign is an operator that negates the value of the literal.Floating point literals can be written in both scientific and decimal form.

Floating point long double literal`3e2L`

= 3 * 10^{2}=`300.0L`

Floating point float literal`3e-2F`

= 3 * 10^{-2}=`0.03F`

The exponent is optional in floating point literals.

`.14`

is the same as`0.14`

Built-in type conversions are implicit by default.

The following rules apply not only for assignment but also usage of a type where another type was expected.

When a

`bool`

variable is assigned an integral value, a value of 0 is converted to`false`

and any other values are converted to`true`

.When a

`bool`

is assigned to an integral type variable, the value of the assigned variable is 1 if the bool was`true`

and 0 if the bool was`false`

When an unsigned integral variable receives a value outside it’s range, the value of the variable “wraps around”. Consider the upper limit of an

`unsigned short`

which is 65,535. It’s`1111 1111 1111 1111`

in binary form. When we add a value of 1 to exceed the upper range it’s the binary value becomes`0000 0001 0000 0000 0000 0000`

which is not 2 bytes anymore but 3. Since it can’t fit the range of our`short`

it’s “wrapped around” by`VALUE modulo MAX_VALUE`

or 65536 % 65536 which is 1.When a signed integral variable receives a value outside it’s range, the result is

*undefined*. The program may crash, produce irrelevant values or the value may get “wrapped around” just like unsigned integrals. For example`short int`

or`short`

has a range of [–32,768..32,767]. If the value 32,768 (`short int`

range + 1) is assigned, the variable will hold the value –32,768. The value we’ve assigned, 32,768 is an integer literal so it would work the same in the following code snippet

```
int a = 32768;
short int b = a;
std::cout << b << std::endl; // Prints –32,768
```

But the important bit is the results are *undefined* thus one shouldn’t write code like this.

- When a floating point type variable is assigned to an integral type variable, the value is truncated. The assigned variable receives the decimal part. (
`int x = 5.89; // x becomes 5`

). If the assigned floating point value is outside the range of the integral variable, the closest value it’s range supports is assigned instead.

```
short x = 12345678.55;
std::cout << x << std::endl; // Prints 32676
short y = -9876543.25;
std::cout << y << std::endl; // Prints -32768
```

One expects the value x to receive only the decimal part of the assigned double value, 12345678 and wrap the type range overflow as if it’s assigned an integral value outside it’s range.

What happens is, the fractional part is truncated and the variable x receives the highest value it’s range supports which is 32676.

- When an integral value is assigned to a floating point variable, the fractional part is set as 0 (
`double val = 50; // val becomes 50.0`

). If the assigned integer has more bits than the floating point variable can hold, precision may be lost.

Don’t mix unsigned and signed types in expressions.

Don’t assign values or variables to variables of types that can’t support their size.