Fundamental Data Types
1. Predefined Data Types
Predefined data types.
| Types | Category | Meaning |
|---|---|---|
| float double long double |
Floating Point | a number with a fractional part |
| bool | Integral (Boolean) | true or false |
| char wchar_t (avoid, win bullshit) char8_t (C++20) (these 3 for unicode) char16_t (C++11) char32_t (C++11) |
Integral (Character) | a single character of text |
| short int long int long long int (C++11) |
Integral (Integer) | positive and negative whole numbers |
| std::nullptr_t (C++11) | Null Pointer | a null pointer |
| void | Void | no type |
In the context of C++, integral means 'like an integer' and includes bool and all the char types. This is because in memory they are stored the same as an integer.
1.1. Integers
An integer is an integral type that can represent positive and negative whole numbers, including 0:
| Type | Minimum Size | Typical Size |
|---|---|---|
| short int | 16 bits | 16 bits |
| int | 16 bits | 32 bits |
| long int | 32 bits | 32 or 64 bits |
| long long int | 64 bits | 64 bits |
In code, the types can be written with or without the suffix int, but the shorter version is preferred. #change
Signed and Unsigned Integers
By default, integers are signedm which means they can be negative and positive.
Unsigned integers can be created with the unsigned keyword:
unsigned short a;
Unsigned integers are useful for networking #stub and systems with little memory, because unsigned integers can store more positive numbers without taking up extra memory, as no negative numbers are required.
Unexpected behaviour can happen when mixing signed and unsigned integers, as in operations the signed integer will be converted to an unsigned integer.
1.2. Floating point types
A float is a type than can hold a number with a fractional component.
| Type | Minimum Size | Typical Size |
|---|---|---|
| float | 32 bits | 32 bits |
| double | 64 bits | 64 bits |
| long double | 64 bits | 64, 96, 128 bits |
The literals for double include suffix . and the ones for float include suffix f.
[!note] Best Practice Use the correct literal for each type. Otherwise an useless conversion will happen.
1.3. Incomplete data types
An incomplete data type is a type that has been declared but not yet defined. The compiler knows about it's existence, but it doesn't know how much memory to allocate to it:
void- represents a lack of type.
Incomplete types cannot be instantiated, but are used in different contexts.
2. Type and Object sizes
The C++ standard does not define the exact size of any fundamental types, only a minimum. However, on most standard systems they are the same:
| Category | Type | Minimum Size | Typical Size |
|---|---|---|---|
| Boolean | bool | 1 byte | 1 byte |
| Character | char wchar_t char8_t (C++20) char16_t (C++11) char32_t (C++11) |
1 byte 1 byte 1 byte 2 bytes 4 bytes |
1 byte 2 or 4 bytes 1 byte 2 bytes 4 bytes |
| Integral | short int long long long |
2 bytes 2 bytes 4 bytes 8 bytes |
2 bytes 4 bytes 4 or 8 bytes 8 bytes |
| Floating point | float double long double |
4 bytes 8 bytes 8 bytes |
4 bytes 8 bytes 8, 12 or 16 bytes |
| Pointer | std::nullptr_t | 4 bytes | 4 or 8 bytes |
In order to determine the size of a type, we can use the sizeof operator. It does not work on dynamically allocated memory.
Types that use less memory aren't always faster. CPU's are often optimized to process data of a certain size (e.g. 32 bits), and types of that size may be processed quicker. #stub
2.2. Fixed-width integers
Sometimes, we need to use types that have an exact size, for this there are fixed-width integers.
| Name | Fixed Size |
|---|---|
| std::int8_t | 1 byte signed |
| std::uint8_t | 1 byte unsigned |
| std::int16_t | 2 bytes signed |
| std::uint16_t | 2 bytes unsigned |
| std::int32_t | 4 bytes signed |
| std::uint32_t | 4 bytes unsigned |
| std::int64_t | 8 bytes signed |
| std::uint64_t | 8 bytes unsigned |
[!warning] std::int8_t and std::uint8_t typically behave like chars (e.g. when printing will display a char)
[!info] Fixed-width integers aren't actually new types, they are just aliases for existing predefined types. E.g.
std::int32_twill be an alias forinton a 32bit system, but on a 16bit system it will be an alias forlonginstead. In most cases the 8 bit ones are an alias for signed and unsignedchar, which is why they behave like one. Other implementations have a special one for 8 bit integers that behaves more like an integer.