Fundamental TypesFundamental TypesFundamental Types

Variable Declarations Variables

Variables of fundamental types are not initialized by default!
int k;  // k not initialized!
cout << k << '\n';  // value might be anything

Because in C++ you only pay for what you use (initilization of large memory blocks can be quite expensive)

But: You should almost always initialize variables when declaring them to prevent bugs!

Quick Overview Overview

Booleans

bool b1 = true
bool b2 = false

Characters

  • smallest integer; usually 1 byte
  • on x86/x86_64 signed ⇒ values ∈ [-128,127]
char c = 'A';  // character literal
char a = 65;   // same as above

Signed Integers

n bits ⇒ values ∈ [-2(n-1), 2(n-1)-1]
short s = 7;        
int   i = 12347;
long  l1 = -7856974990l ;
long long  l2 = 89565656974990ll;

int x = 0x4A; // hexadecimal literal int b = 0b10110101; // binary literal 
long l2 = 512'232'697'499; // ' separator 

Unsigned Integers

n bits ⇒ values ∈ [0, 2n]
unsigned u1 = 12347u ; 
unsigned long u2 = 123478912345ul;  
unsigned long long u3 = 123478912345ull;

Floating Point Types

  • float usually IEEE-754 32 bit
  • double usually IEEE-754 64 bit
  • long double usually 80-bit on x86/x86-64
float       f  = 1.88f;
double      d1 = 3.5e38;
long double d2 = 3.5e38l; 

double d3 = 512'232'697'499.052; // ' separator 

Arithmetic Operations Arithmetic

  • expression a b returns result of operation ⊕ applied to the values of a and b
  • expression a ⊕= b stores result of operation ⊕ in a
int a = 4; 
int b = 3; 

a = a + b; a += b;
a = a b; a -= b;
a = a * b; a *= b;
a = a / b; a /= b;
a = a % b;
variable a is set to value 4
variable b is set to value 3

a: 7 add a: 10
a: 7 subtract a: 4
a: 12 multiply a: 36
a: 12 divide a: 4
a: 1 remainder of division (modulo)modulo

Increment/Decrement Increment

  • changes value by +/- 1
  • prefix expressions ++x / --x returns new (incremented/decremented) value
  • postfix expression x++ / x-- incrementes/decrementes value, but returns old value
int a = 4;
int b = 3;

b = a++; b = ++a;
b = --a; b = a--;
a: 4
        b: 3

a: 5 b: 4 a: 6 b: 6
a: 5 b: 5 a: 4 b: 5

Comparisons

2-way Comparisons

result of comparison is either true or false}

int x = 10;                       
int y = 5;                       

bool b1 = x == 5; bool b2 = (x != 6);
bool b3 = x > y; bool b4 = x < y; bool b5 = y >= 5; bool b6 = x <= 30;

result  operator

false equals true not equal
true greater false smaller true greater/equal true smaller/equal
3-Way Comparisons With <=>
(a <=> b) is < 0   if a < b
(a <=> b) is == 0  if a and b are equal
(a <=> b) is > 0   if a > b

3-way comparisons don't actually return a number but a special comparison category object that copares less, equal or greater than 0.

Boolean Logic

bool a = true;
bool b = false;
bool c = a && b;   // false    logical AND
bool d = a || b;   // true     logical OR
bool e = !a;       // false    logical NOT
Conversion to bool
  • 0 is always false
  • everything else is true
bool f = 12;   // true   (int → bool)
bool g = 0;    // false  (int → bool)
bool h = 1.2;  // true   (double → bool)
Short-circuit Evaluation

The second operand of a boolean comparison is not evaluated if the result is already known after evaluating the first operand.

int i = 2;  
int k = 8;
bool b1 = (i > 0) || (k < 3);
i > 0 is already truek < 3 is not evaluated, because the result of logical OR is already true

Memory Sizes of Fundamental Types Fundamental Memory Sizes Memory Sizes

std::numeric_limits<type> numeric_limits

#include <limits>
// largest positive value:
std::numeric_limits<double>::max()     
// smallest value > 0:
std::numeric_limits<double>::min()     
// smallest negative value:
std::numeric_limits<double>::lowest()  
// smallest difference btw. 1 and next value:
std::numeric_limits<double>::epsilon() 
…
#include <limits>
std::numeric_limits<double>::max()     // largest positive value
std::numeric_limits<double>::min()     // smallest value > 0
std::numeric_limits<double>::lowest()  // smallest negative value
std::numeric_limits<double>::epsilon() // smallest difference btw. 1 and next value

Type Narrowing Narrowing

  • conversion from type that can represent more values to one that can represent less
  • may result in loss of information
  • in general no compiler warning – happens silently
  • potential source of subtle runtime bugs
double   d = 1.23456;
float    f = 2.53f;
unsigned u = 120u;

double e = f; // OK float → double
int i = 2.5; // NARROWING double → int int j = u; // NARROWING unsigned int → int int k = f; // NARROWING float → int

Braced Initialization

type variable { value };
  • works for all fundamental types
  • narrowing conversion ⇒ compiler warning
double   d {1.23456};  // OK
float    f {2.53f};    // OK
unsigned u {120u};     // OK

double e {f}; // OK float → double
int i {2.5}; // COMPILER WARNING: double → int int j {u}; // COMPILER WARNING: unsigned int → int int k {f}; // COMPILER WARNING: float → int

Make sure to prevent silent type conversions, especially narrowing unsigned to signed integer conversions — they can cause hard-to-find runtime bugs!