Learn C++ with Qt, Part 006: Standard data types


As a continuation of part 5 of this tutorial this part takes a closer look at the standard data types in C++ which can be used for the definition of variables or constants. This is another important building block that you need in order to write your own programs.

Standard data types for variables

For the definition of variables in a typical program, you have to know that there are two different groups of variables – not counting in object types: variables which use standard data types and variables which use self-defined data types (which are built up upon the standard types).

The standard data types in C++ (and other programming languages) can handle integer numbers, floating point numbers, single characters or strings of characters in different variations. Apart from a simple value these kinds of types can be combined and used to handle all kinds of data in your program, like images, sounds, music, video etc.

While I’ve put in some standard values for the memory size that is needed by the different standard data types in the following tables, these values are not the same on every platform. You have to look up the exact value for your programming (or target) computing platform in the documentation for the C++ compiler that you are using.

The only exception are the character types “char16_t” and “char32_t” which are fixed to use 16 or 32 bit on every platform, just like their names imply.

Standard C and C++ data types

So what are these basic data types and which type keywords do you need in order to define a variable of this type?

In the following tables, you can see the standard data types for C++, split up into different type groups:

C++ character data types

If you want to handle single characters – for single key inputs or as part of manipulating a bigger text – you need to define a variable with one of the following type keywords for character-based data types:

Type name Size (bits) Remarks
char 8 or more For ASCII characters and in classic implementations, only 8 bits (1 byte) are used for a single character. Modern systems often use Unicode characters which need at least 2 bytes (in Microsoft’s C#, char is automatically a structure with two bytes so it can store Unicode characters).
char16_t 16 or more This type uses 16 bits (2 bytes) as a minimum, so it is as least as big (in terms of memory size) as char. Typically it uses double the amount of memory that char uses.
char32_t 32 or more This character type uses at least 32 bits, and typically is double the size of char16_t in the given development environment.
wchar_t 32 or more This data type can represent the largest character set that is supported on the target plattform. Typically its size is at least 32 bits (4 bytes), which is currently enough for the full spectrum of Unicode characters.
string 8 or more In the classic C programming language, string was also a character-based standard data type. It can store an undefined amount of characters (one or more), and the end of the string is marked by a null character (a byte with the value zero). In C++ (and C#), strings are usually implemented as objects – more on that later.

Here are some short examples for the definition and usage of character data type variables:

char mychar; wchar_t widechar; string message; mychar = 'M'; widechar = 0x41; message = 'This is a string.'; cout << mychar << widechar << endl; cout << message;

C++ signed integer types

Integer numbers require another kind of data type in order for a variable value to be used as part of a computation.

In the C and C++ programming language – and other languages derived from them, like C# - integer type definitions can have an additional prefix keyword in order to define if the values stored in the variable can have a sign for negative values or if only positive values are used.

The different integer types for signed values that are available in C++ are the following:

Type name Size (bits) Remarks
signed char 8 or more While this is a character, the additional “signed” keyword marks it as being equal to an integer value where the first bit is interpreted as a sign value. Depending on the first bit, the rest of the bits represent a positive or negative integer value.
signed short int 16 or more This data type is intended to store a smaller integer value which can be positive or negative. Memorysize-wise, it is no smaller than “signed char”, but usually smaller as a normal “signed int”.
signed int 16 or more The default integer type with added sign prefix. It uses at least 16 bits, but compared to “unsigned int”, the range of possible values is half as big as it loses one bit in order to represent the sign value.
signed long int 32 or more This data type typically uses double the amount of bytes that “signed int” uses, so the value range is a lot bigger.
signed long long int 64 or more The “long long” version of “signed int” uses twice the amount of bytes that “signed long int” uses, so range of possible values even bigger. Use this when you need to handle really big numbers.

The C and C++ programming languages allow the names of certain integer types to be abbreviated for integer variable definitions. For signed integer types, you can use the following abbreviations:

Full data type name Abbreviated data type name
signed short int short
signed int int
signed long int long
signed long long int long long

Here is a short example for the usage of different signed integer types:

int x = 2; signed long y = 8; long z; z = x + y; cout x << ' + ' << y << ' = ' << z;

C++ unsigned integer types

The unsigned integer types use the same amount of memory as their related signed integer type counterparts, but the first bit is used to store an actual value instead of the sign information. This enables the unsigned integer variables to store bigger values.

If an integer variable is defined without the prefix keyword “signed” or “unsigned”, the compiler usually assumes that you want to use the signed version of the currently used integer type for the variable. So if that is your intention, you can leave out the additional keyword, otherwise you should add it.

Here are the unsigned integer data types which you can use in C++:

Type name Size (bits) Remarks
unsigned char 8 or more As with “signed char”, this is a character that represents an integer value. Without the sign information, all bits can be used for storing the value – with an 8-bit character, that would be 256 possible values (from zero to 255), and 65536 values for a 16-bit character.
unsigned short int 16 or more This data type is intended to store a smaller integer value without sign information. Size-wise, it is no smaller than “unsigned char”, but usually smaller as a normal “unsigned int”.
unsigned int 16 or more The default integer type. It uses at least 16 bits, so the minimum range of possible values lies between zero and 65535.
unsigned long int 32 or more This data type typically uses double the amount of bytes that “unsigned int” uses, so the value range is a lot bigger.
unsigned long long int 64 or more This “long long” version of “unsigned int” uses twice the amount of bytes that “unsigned long int” uses, so range of possible values even bigger. For truly big numbers.
Full data type name Abbreviated data type name
unsigned short int unsigned short
unsigned int unsigned
unsigned long int unsigned long
unsigned long long int unsigned long long

Just as with the signed integer types, you can use abbreviated forms for the definition of unsigned integer variables:

Here is a short example for unsigned integer variables:

unsigned int value; unsigned long squarevalue; value = 16; squarevalue = value * value; cout << "The square value of " << value << " is " << squarevalue;

C++ floating-point data types

For a lot of calculations, integer values are not enough – you need floating point (or fixed point) values with some additional decimals behind the comma. In this case, you can use one of the following data types in order to define floating point variables:

Type name Size (bits) Remarks
float 8 or more This data type can store small floating point numbers – integer values with added decimals behind a floating point (mathematical comma).
double 16 or more With “double”, you can use bigger floating point values than with “float”. As more bits can be used for the decimals behind the comma, the precision the represented (usually computed) value is typically higher that with “float”.
long double 16 or more A “long double” variable normally uses twice the amount of memory that a “double” variable uses. This allows bigger values and more precision in calculations.

This is an example for using floating point variables:

float a = 0.25; double b = 1.24995873;

If you want to use variables of different data types  - like "int" and "float" for example - as part of the same computation (adding, subtracting, assigning the result to another variable etc.), you need to be careful.

Some operations allow the combination of variables or constants with different data types, while others require you to use variables or constants of the same data type. And assigning the result of an operation to a variable of a different type can lead to a type conversion error or to the result being incomplete (e.g. dropping any decimals).

Problems like these can be avoided by using type casting or special type conversion functions. More on that in a later part of this tutorial.

C++ Boolean data type

Sometimes you just want to store the value for a single option or switch or something similar where just two different values are possible – true or false, on or off etc. This can be done by defining a variable using the Boolean data type.

As the name implies, this is the basic type for operations using the Boolean algebra and binary logic. The name comes from George Boole, who first defined an algebraic system of logic in the mid 19th century.

There is just one standard Boolean data type in C and C++:

Type name Size (bits) Remarks
bool 8 As the computer cannot directly address single bits inside the memory – just blocks of at least one or two bytes – a full byte (8 bits) are needed to store a Boolean value, even though only one of the bits is actually used.

Although the actual value of a variable of the “bool” type is stored as a number value (typically using 8 bits), the value assignment – or value comparison as part of a Boolean condition check (more on that later) – is done using the “true” and “false” keywords in C++:

bool myBoolValue; bool yourBoolValue = false; myBoolValue = true;

C++ void data type

The void data type is somewhat special. As the name implies, it logically  represents a void, so it cannot store any value.

Because of this, the void type is not used for standard variable definitions, but rather for the definition of procedures (which are functions that do not directly return a value) and memory pointers. The “void” value is only a memory address, without additional information about the size of memory that is used starting at this address.

While the usage of void pointers – or other pointer types – can be problematic, they allow you to read and write to the computer’s memory at the lowest level, which can be useful for direct access to the underlying hardware.

Type name Size (bits) Remarks
void 16 or more While “void” does not store any specific value and therefore does not need memory storage space, the memory address that it points at usually needs 16 bits or more. Current systems use 64 bits, older ones 16 or 32 bits, and future systems will likely use 128 bits or more. With bigger values, more memory can be accessed.

The definition of a function returning a void value - and therefore no value - looks like this:

void MyProcedure( int x, int y );

C++ null pointer data type

The null pointer is another special case. Usually the “nullptr” keyword is used to initialize or reset the values of objects, or to check if the object contains valid data. “nullptr” is a pointer literal of type “std::nullptr_t”, so you can use “nullptr_t” to define a variable that is just a null pointer.

Type name Size (bits) Remarks
nullptr_t
decltype(nullptr)
16 or more The amount of memory that a null pointer needs is the same as for a void pointer.

Similar to the “void” data type, the null pointer is not a full type, just a memory address.

The following example declares a function that takes only a nullptr (or a value cast to std::nullptr_t) as its single argument:

void func( std::nullptr_t );

In the C programming language as well as in older C++ variations, the “NULL” keyword was used instead of the null pointer. Currently, most C++ compilers support the “C++11” standard, which allows you to use “nullptr” and “std::nullptr_t”. This will tell the compiler that you explicitly use or declare a pointer to a null value.

Summary

The data types listed above represent the basic types that you can use for your variables. If you do not count different variations of the same basic type, the list is relatively short. Even though, most kinds of data that you want to use and compute with your programs can be represented by these types or at least by a combination of variables using these types.

More advanced types can be defined by combining different variables of different or similar types into self-defined structures. But this is a topic for another article in this tutorial series...