Modern C++
Programming
2. Basic Concepts I
Fundamental Types and Operators
Federico Busato
2024-01-26
Table of Contents
1 Preparation
What compiler should I use?
What editor/IDE compiler should I use?
How to compile?
2 Hello World
I/O Stream
1/42
Table of Contents
3 Fundamental Types Overview
Arithmetic Types
Arithmetic Types - Suffix and Prefix
Non-Standard Arithmetic Types
void Type
nullptr
2/42
Table of Contents
4 Conversion Rules
5 auto Declaration
6 C++ Operators
Operators Precedence
Prefix/Postfix Increment/Decrement Semantic
Assignment, Compound, and Comma Operators
Spaceship Operator <=>
Safe Comparison Operators
3/42
Preparation
What Compiler Should I Use?
Most popular compilers:
Microsoft Visual Code (MSVC) is the compiler offered by Microsoft
The GNU Compiler Collection (GCC) contains the most popular C++ Linux
compiler
Clang is a C++ compiler based on LLVM Infrastructure available for
Linux/Windows/Apple (default) platforms
Suggested compiler on Linux for beginner: Clang
Comparable performance with GCC/MSVC and low memory usage
Expressive diagnostics (examples and propose corrections)
Strict C++ compliance. GCC/MSVC compatibility (inverse direction is not ensured)
Includes very useful tools: memory sanitizer, static code analyzer, automatic formatting,
linter, etc.
4/42
Install the Compiler on Linux
Install the last gcc/g++ (v11) (v12 on Ubuntu 22.04)
$ sudo add-apt-repository ppa:ubuntu-toolchain-r/test
$ sudo apt update
$ sudo apt install gcc-12 g++-12
$ gcc-12 --version
Install the last clang/clang++ (v17)
$ bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)"
$ wget https://apt.llvm.org/llvm.sh
$ chmod +x llvm.sh
$ sudo ./llvm.sh 17
$ clang++ --version
5/42
Install the Compiler on Windows
Microsoft Visual Studio
Direct Installer: Visual Studio Community 2022
Clang on Windows
Two ways:
Windows Subsystem for Linux (WSL)
Run optionalfeatures
Select Windows Subsystem for Linux , Hyper-V ,
Virtual Machine Platform
Run ms-windows-store: Search and install Ubuntu 22.04 LTS
Clang + MSVC Build Tools
Download Build Tools per Visual Studio
Install Desktop development with C++
6/42
What Editor/IDE Compiler Should I Use? 1/3
Popular C++ IDE (Integrated Development Environment):
Microsoft Visual Studio (MSVC) (link). Most popular IDE for Windows
Clion (link). (free for student). Powerful IDE with a lot of options
QT-Creator (link). Fast (written in C++), simple
XCode. Default on Mac OS
Cevelop (Eclipse) (link)
Standalone GUI-based coding editors:
Microsoft Visual Studio Code (VSCode) (link)
Sublime (link)
Lapce (link)
7/42
What Editor/IDE Compiler Should I Use? 2/3
Standalone text-based coding editors (powerful, but needs expertise):
Vim
Emacs
NeoVim (link)
Helix (link)
Not suggested: Notepad, Gedit, and other similar editors (lack of support for
programming)
8/42
What Editor/IDE Compiler Should I Use? 3/3
StackOverflow Developer Survey 2022
9/42
How to Compile?
Compile C++11, C++14, C++17, C++20 programs:
g++ -std=c++11 <program.cpp> -o program
g++ -std=c++14 <program.cpp> -o program
g++ -std=c++17 <program.cpp> -o program
g++ -std=c++20 <program.cpp> -o program
Any C++ standard is backward compatible
C++ is also backward compatible with C (even for very old code) except if it contains
C++ keywords (new, template, class, typename, etc.)
We can potentially compile a pure C program in C++20
10/42
C++ Standard 1/2
Compiler
C++11 C++14 C++17 C++20
Core Library Core Library Core Library Core Library
g++ 4.8.1 5.1 5.1 5.1 7.1 9.0 11+ 11+
clang++ 3.3 3.3 3.4 3.5 5.0 11.0 16+ 16+
MSVC 19.0 19.0 19.10 19.0 19.15 19.15 19.29+ 19.29
en.cppreference.com/w/cpp/compiler support
11/42
C++ Standard 2/2
12/42
Hello World
Hello World 1/2
C code with printf :
#include <stdio.h>
int main() {
printf("Hello World!\n");
}
printf
prints on standard output
C++ code with streams :
#include <iostream>
int main() {
std::cout << "Hello World!\n";
}
cout
represents the standard output stream
13/42
Hello World 2/2
The previous example can be written with the global std namespace:
#include <iostream>
using namespace std;
int main() {
cout << "Hello World!\n";
}
Note: For sake of space and for improving the readability, we intentionally omit the
std namespace in most slides
14/42
I/O Stream (std::cout) 1/3
std::cout is an example of output stream. Data is redirected to a destination, in
this case the destination is the standard output
#include <stdio.h>
int main() {
int a = 4;
double b = 3.0;
char c[] = "hello";
printf("%d %f %s\n", a, b, c);
}
#include <iostream>
int main() {
int a = 4;
double b = 3.0;
char c[] = "hello";
std::cout << a << " " << b << " " << c << "\n";
}
15/42
C:
C++:
I/O Stream (Why should we prefer I/O stream?) 2/3
Type-safe: The type of object provided to the I/O stream is known statically by the
compiler. In contrast, printf uses % fields to figure out the types dynamically
Less error prone: With I/O Stream, there are no redundant % tokens that have to
be consistent with the actual objects passed to I/O stream. Removing redundancy
removes a class of errors
Extensible: The C++ I/O Stream mechanism allows new user-defined types to be
passed to I/O stream without breaking existing code
Comparable performance: If used correctly may be faster than C I/O ( printf ,
scanf , etc.) .
16/42
I/O Stream (Common C errors) 3/3
Forget the number of parameters:
printf("long phrase %d long phrase %d", 3);
Use the wrong format:
int a = 3;
...many lines of code...
printf(" %f", a);
The %c conversion specifier does not automatically skip any leading white space:
scanf("%d", &var1);
scanf(" %c", &var2);
17/42
std::print
C++23 introduces an improved version of printf function std::print based on
formatter strings that provides all benefits of C++ stream and is less verbose
#include <print>
int main() {
std::print("Hello World! {}, {}, {}\n", 3, 4ll, "aa");
// print "Hello World! 3 4 aa"
}
This will be the default way to print when the C++23 standard is widely adopted
18/42
Fundamental Types
Overview
Arithmetic Types - Integral
Native Type Bytes Range
Fixed width types
<cstdint>
bool 1 true, false
char
1 implementation defined
signed char 1 -128 to 127 int8 t
unsigned char 1 0 to 255 uint8 t
short 2 -2
15
to 2
15
-1 int16 t
unsigned short 2 0 to 2
16
-1 uint16 t
int 4 -2
31
to 2
31
-1 int32 t
unsigned int 4 0 to 2
32
-1 uint32 t
long int 4/8
int32 t/int64 t
long unsigned int 4/8
uint32 t/uint64 t
long long int 8 -2
63
to 2
63
-1 int64 t
long long unsigned int 8 0 to 2
64
-1 uint64 t
4 bytes on Windows64 systems,
signed/unsigned, two-complement from C++11
19/42
Arithmetic Types - Floating-Point
Native Type IEEE Bytes Range
Fixed width types
C++23 <stdfloat>
(bfloat16) N 2 ±1.18 × 10
38
to ±3.4 × 10
+38
std::bfloat16 t
(float16) Y 2 0.00006 to 65, 536 std::float16 t
float Y 4 ±1.18 × 10
38
to ±3.4 × 10
+38
std::float32 t
double Y 8 ±2.23 × 10
308
to ±1.8 × 10
+308
std::float64 t
20/42
Arithmetic Types - Short Name
Signed Type short name
signed char /
signed short int short
signed int int
signed long int long
signed long long int long long
Unsigned Type short name
unsigned char /
unsigned short int unsigned short
unsigned int unsigned
unsigned long int unsigned long
unsigned long long int unsigned long long
21/42
Arithmetic Types - Suffix (Literals)
Type SUFFIX Example Notes
int / 2
unsigned int u, U 3u
long int l, L 8L
long unsigned ul, UL 2ul
long long int ll, LL 4ll
long long unsigned int ull, ULL 7ULL
float f, F 3.0f only decimal numbers
double 3.0 only decimal numbers
C++23 Type SUFFIX Example Notes
std::bfloat16 t bf16, BF16 3.0bf16 only decimal numbers
std::float16 t f16, F16 3.0f16 only decimal numbers
std::float32 t f32, F32 3.0f32 only decimal numbers
std::float64 t f64, F64 3.0f64 only decimal numbers
std::float128 t f128, F128 3.0f128 only decimal numbers
22/42
Arithmetic Types - Prefix (Literals)
Representation PREFIX Example
Binary C++14 0b 0b010101
Octal 0 0307
Hexadecimal 0x or 0X 0xFFA010
C++14 also allows digit separators for improving the readability 1'000'000
23/42
Other Arithmetic Types
C++ also provides long double (no IEEE-754) of size 8/12/16 bytes
depending on the implementation
Reduced precision floating-point supports before C++23:
- Some compilers provide support for half (16-bit floating-point) (GCC for ARM: fp16 ,
LLVM compiler: half )
- Some modern CPUs and GPUs provide half instructions
- Software support: OpenGL, Photoshop, Lightroom, half.sourceforge.net
C++ does not provide 128-bit integers even if some architectures support it.
clang and gcc allow 128-bit integers as compiler extension ( int128 )
24/42
void Type
void is an incomplete type (not defined) without a value
void indicates also a function with no return type or no parameters
e.g. void f() , f(void)
In C sizeof(void) == 1 (GCC), while in C++ sizeof(void) does not
compile!!
int main() {
// sizeof(void); // compile error
}
25/42
nullptr Keyword
C++11 introduces the new keyword nullptr to represent a null pointer ( 0x0 ) and
replacing the NULL macro
int* p1 = NULL; // ok, equal to int* p1 = 0l
int* p2 = nullptr; // ok, nullptr is a pointer not a number
int n1 = NULL; // ok, we are assigning 0 to n1
// int n2 = nullptr; // compile error we are assigning
// a null pointer to an integer variable
// int* p2 = true ? 0 : nullptr; // compile error
// incompatible types
Remember: nullptr is not a pointer, but an object of type nullptr
t safer
26/42
Fundamental Types Summary
The fundamental types, also called primitive or built-in, are organized into three
main categories:
Integers
Floating-points
void , nullptr
Any other entity in C++ is
an alias to the correct type depending to the context and the architectures
a composition of builtin types: struct/class, array, union
en.cppreference.com/w/cpp/language/types
en.cppreference.com/w/cpp/types/integer
27/42
C++ Types Summary
28/42
Conversion Rules
Conversion Rules
Implicit type conversion rules, applied in order, before any operation:
: any operation (*, +, /, -, %, etc.)
(A) Floating point promotion
floating type integer type floating type
(B) Implicit integer promotion
small integral type := any signed/unsigned integral type smaller than int
small integral type small integral type int
(C) Size promotion
small type large type large type
(D) Sign promotion
signed type unsigned type unsigned type
29/42
Examples and Common Errors
float f = 1.0f;
unsigned u = 2;
int i = 3;
short s = 4;
uint8_t c = 5; // unsigned char
f * u; // float × unsigned float: 2.0f
s * c; // short × unsigned char int: 20
u * i; // unsigned × int unsigned: 6u
+c; // unsigned char int: 5
Integers are not floating points!
int b = 7;
float a = b / 2; // a = 3 not 3.5!!
int c = b / 2.0; // again c = 3 not 3.5!!
30/42
Implicit Promotion
Integral data types smaller than 32-bit are implicitly promoted to int , independently
if they are signed or unsigned
Unary +, -, and Binary +, -, &, etc. promotion:
char a = 48; // '0'
cout << a; // print '0'
cout << +a; // print '48'
cout << (a + 0); // print '48'
uint8_t a1 = 255;
uint8_t b1 = 255;
cout << (a1 + b1); // print '510' (no overflow)
31/42
auto Declaration
auto Keyword 1/3
C++11 The auto keyword specifies that the type of the variable will be automatically
deduced by the compiler (from its initializer)
auto a = 1 + 2; // 1 is int, 2 is int, 1 + 2 is int!
// -> 'a' is "int"
auto b = 1 + 2.0; // 1 is int, 2.0 is double. 1 + 2.0 is double
// -> 'b' is "double"
auto can be very useful for maintainability and for hiding complex type definitions
for (auto i = k; i < size; i++)
...
On the other hand, it may make the code less readable if excessively used because of
type hiding
Example: auto x = 0; in general makes no sense ( x is int )
32/42
auto Keyword - Functions
2/3
In C++11/C++14, auto (as well as decltype ) can be used to define function
output types
auto g(int x) -> int { return x * 2; } // C++11
// "-> int" is the deduction type
// a better way to express it is:
auto g2(int x) -> decltype(x * 2) { return x * 2; } // C++11
auto h(int x) { return x * 2; } // C++14
//--------------------------------------------------------------
int x = g(3); // C++11
33/42
auto Keyword - Functions
3/3
In C++20, auto can be also used to define function input
void f(auto x) {}
// equivalent to templates but less expensive at compile-time
//--------------------------------------------------------------
f(3); // 'x' is int
f(3.0); // 'x' is double
34/42
C++ Operators
Operators Overview
Precedence Operator Description Associativity
1 a++ a-- Suffix/postfix increment and decrement Left-to-right
2
+a -a ++a --a
! not
Plus/minus, Prefix increment/decrement,
Logical/Bitwise Not
Right-to-left
3 a*b a/b a%b Multiplication, division, and remainder Left-to-right
4 a+b a-b Addition and subtraction Left-to-right
5 Bitwise left shift and right shift Left-to-right
6 < <= > >= Relational operators Left-to-right
7 == != Equality operators Left-to-right
8 & Bitwise AND Left-to-right
9 ˆ Bitwise XOR Left-to-right
10 | Bitwise OR Left-to-right
11 && and Logical AND Left-to-right
12 || or Logical OR Left-to-right
13
+= -= *= /= %=
<<= >>= &= ˆ= |=
Compound Right-to-left
35/42
Operators Precedence 1/2
Unary operators have higher precedence than binary operators
Standard math operators (+, *, etc.) have higher precedence than
comparison, bitwise, and logic operators
Bitwise and logic operators have higher precedence than comparison operators
Bitwise operators have higher precedence than logic operators
Compound assignment operators += , -= , *= , /= , %= , ˆ= , != , &= ,
>>= , <<= have lower priority
The comma operator has the lowest precedence (see next slides)
en.cppreference.com/w/cpp/language/operator precedence
36/42
Operators Precedence 2/2
Examples:
a + b * 4; // a + (b * 4)
a * b / c % d; // ((a * b) / c) % d
a + b < 3 >> 4; // (a + b) < (3 >> 4)
a && b && c || d; // (a && b && c) || d
a and b and c or d; // (a && b && c) || d
a | b & c || e && d; // ((a | (b & c)) || (e && d)
Important: sometimes parenthesis can make an expression verbose... but they can
help!
37/42
Prefix/Postfix Increment Semantic
Prefix Increment/Decrement ++i , --i
(1) Update the value
(2) Return the new (updated) value
Postfix Increment/Decrement i++ , i--
(1) Save the old value (temporary)
(2) Update the value
(3) Return the old (original) value
Prefix/Postfix increment/decrement semantic applies not only to built-in types but
also to objects
38/42
Operation Ordering Undefined Behavior
Expressions with undefined (implementation-defined) behavior:
int i = 0;
i = ++i + 2; // until C++11: undefined behavior
// since C++11: i = 3
i = 0;
i = i++ + 2; // until C++17: undefined behavior
// since C++17: i = 3
f(i = 2, i = 1); // until C++17: undefined behavior
// since C++17: i = 2
i = 0;
a[i] = i++; // until C++17: undefined behavior
// since C++17: a[1] = 1
f(++i, ++i); // undefined behavior
i = ++i + i++; // undefined behavior
39/42
Assignment, Compound, and Comma Operators
Assignment and compound assignment operators have right-to-left associativity
and their expressions return the assigned value
int y = 2;
int x = y = 3; // y=3, then x=3
// the same of x = (y = 3)
if (x = 4) // assign x=4 and evaluate to true
The comma operator
has left-to-right associativity. It evaluates the left expression,
discards its result, and returns the right expression
int a = 5, b = 7;
int x = (3, 4); // discards 3, then x=4
int y = 0;
int z;
z = y, x; // z=y (0), then returns x (4)
40/42
Spaceship Operator <=>
C++20 provides the three-way comparison operator <=> , also called spaceship
operator, which allows comparing two objects in a similar way of strcmp . The
operator returns an object that can be directly compared with a positive, 0, or negative
integer value
(3 <=> 5) == 0; // false
('a' <=> 'a') == 0; // true
(3 <=> 5) < 0; // true
(7 <=> 5) < 0; // false
The semantic of the spaceship operator can be extended to any object (see next
lectures) and can greatly simplify the comparison operators overloading
41/42
Safe Comparison Operators
C++20 introduces a set of functions <utility> to safely compare integers of
different types (signed, unsigned)
bool cmp_equal(T1 a, T2 b)
bool cmp_not_equal(T1 a, T2 b)
bool cmp_less(T1 a, T2 b)
bool cmp_greater(T1 a, T2 b)
bool cmp_less_equal(T1 a, T2 b)
bool cmp_greater_equal(T1 a, T2 b)
example:
# include <utility>
unsigned a = 4;
int b = -3;
bool v1 = (a > b); // false!!!, see next slides
bool v2 = std::cmp_greater(a, b); // true
How to compare signed and unsigned integers in C++20?
42/42