Lecture 3-2: Operator & expression (1)

operators & priority

increment & decrement

opeartorsyntax
pre-increment++a
pre-decrement--a
post-incrementa++
post-decrementa--
#include <iostream>

int main()
{
  int n1 = 1;
  int n2 = ++n1;
  int n3 = ++++n1;
  int n4 = n1++;
//int n5 = n1++ ++;   // error
//int n6 = n1 + ++n1; // undefined behavior
  std::cout << "n1 = " << n1 << '\n'
            << "n2 = " << n2 << '\n'
            << "n3 = " << n3 << '\n'
            << "n4 = " << n4 << '\n';
}

NOTE: demo with debugger

$ ./a.out
n1 = 5
n2 = 2
n3 = 4
n4 = 4
$

arithmic operators

opeartorsyntax
unary plus+a
unary minus-a
additiona + b
subtractiona - b
multiplicationa * b
divisiona / b
moduloa % b

+a & -a

#include <iostream>
int main()
{
  char c = 0x6a;
  int n1 = 1;
  unsigned char n2 = 1;
  unsigned int n3 = 1;
  std::cout << "char: " << c << " int: " << +c << '\n'
            << "-1, where 1 is signed: " << -n1 << '\n'
            << "-1, where 1 is unsigned char: " << -n2 << '\n'
            << "-1, where 1 is unsigned int: " << -n3 << '\n';
}
$ ./a.out
char: j int: 106
-1, where 1 is signed: -1
-1, where 1 is unsigned char: -1
-1, where 1 is unsigned int: 4294967295
$

a % b

#include <iostream>
int main()
{
  char c = 2;
  unsigned int un = 2;
  int n = -10;
  std::cout << "2 * (-10), where 2 is a char    = " << c * n << '\n'
            << "2 * (-10), where 2 is unsigned  = " << un * n << '\n'
            << "-10 / 2.12  = " << n / 2.12 << '\n'
            << "-10 / 21  = " << n / 21 << '\n'
            << "-10 % 21  = " << n % 21 << '\n';
}
$ ./a.out
2 * (-10), where 2 is a char    = -20
2 * (-10), where 2 is unsigned  = 4294967276
-10 / 2.12  = -4.71698
-10 / 21  = 0
-10 % 21  = -10
$

bitwise operator

opeartorsyntax
bitwise NOT~a
bitwise ANDa & b
bitwise ORa \| b
bitwise XORa ^ b
bitwise left shifta << b
bitwise right shifta >> b

~a, a & b, a | b, a ^ b

Truth table:

a = 0a = 1
~a10
a & ba = 0a = 1
b = 000
b = 101
a \| ba = 0a = 1
b = 001
b = 111
a ^ ba = 0a = 1
b = 001
b = 110
#include <iostream>
#include <iomanip>
#include <bitset> // include for display binary number
int main()
{
  uint16_t mask = 0x00f0;
  uint32_t x0 = 0x12345678;
  uint32_t x1 = x0 | mask;
  uint32_t x2 = x0 & ~mask;
  uint32_t x3 = x0 & mask;
  uint32_t x4 = x0 ^ mask;
  uint32_t x5 = ~x0;
  using bin16 = std::bitset<16>;         // display in 16-bit width binary number
  using bin32 = std::bitset<32>;         // display in 32-bit width binary number
  std::cout << std::hex << std::showbase // show in hexdecemal with base number (0x)
            << "Mask: " << mask << std::setw(49) << bin16(mask) << '\n'
            << "Value: " << x0 << std::setw(42) << bin32(x0) << '\n'
            << "Setting bits: " << x1 << std::setw(35) << bin32(x1) << '\n'
            << "Clearing bits: " << x2 << std::setw(34) << bin32(x2) << '\n'
            << "Selecting bits: " << x3 << std::setw(39) << bin32(x3) << '\n'
            << "XOR-ing bits: " << x4 << std::setw(35) << bin32(x4) << '\n'
            << "Inverting bits: " << x5 << std::setw(33) << bin32(x5) << '\n';
}
$ ./a.out
Mask: 0xf0                                 0000000011110000
Value: 0x12345678          00010010001101000101011001111000
Setting bits: 0x123456f8   00010010001101000101011011111000
Clearing bits: 0x12345608  00010010001101000101011000001000
Selecting bits: 0x70       00000000000000000000000001110000
XOR-ing bits: 0x12345688   00010010001101000101011010001000
Inverting bits: 0xedcba987 11101101110010111010100110000111
$

a >> b & a << b

#include <iostream>
int main()
{
  std::cout << std::hex << std::showbase;
  char c = 0x10;
  unsigned long long ull = 0x123;
  std::cout << "0x123 << 1 = " << (ull << 1) << '\n'
            << "0x123 << 63 = " << (ull << 63) << '\n' // overflow in unsigned
            << "0x10 << 10 = " << (c << 10) << '\n';   // char is promoted to int
  long long ll = -1000;
  std::cout << std::dec << "-1000 >> 1 = " << (ll >> 1) << '\n';
}
$ ./a.out
0x123 << 1 = 0x246
0x123 << 63 = 0x8000000000000000
0x10 << 10 = 0x4000
-1000 >> 1 = -500
$

logical operators

opeartorsyntax
negation!a
ANDa && b
inclusive ORa \|\| b

Truth table:

a = falsea = true
!atruefalse
a && ba = falsea = true
b = falsefalsefalse
b = truefalsetrue
a \|\| ba = falsea = true
b = falsefalsetrue
b = truetruetrue
#include <iostream>
int main()
{
  bool a = true;
  bool b = false;
  std::cout << std::boolalpha
            << "a: " << a << std::endl
            << "b: " << b << std::endl
            << "!a: " << !a << std::endl
            << "a && b: " << a &&
          b << std::endl
            << "a || b: " << a ||
      b << std::endl;
  return 0;
}
$ ./a.out
a: true
b: false
!a: false
a && b: false
a || b: true
$

comparison operators

opeartorsyntax
equal toa == b
not equal toa != b
less thana < b
greater thana > b
less than or equal toa <= b
greater than or equal toa >= b
#include <iostream>
int main()
{
  std::cout << std::boolalpha;
  int n = -1;

  int n2 = 1;
  std::cout << " -1 == 1? " << (n == n2) << '\n'
            << "Comparing two signed values:\n"
            << " -1  < 1? " << (n < n2) << '\n'
            << " -1  > 1? " << (n > n2) << '\n';

  unsigned int u = 1;
  std::cout << "Comparing signed and unsigned:\n"
            << " -1  < 1? " << (n < u) << '\n'
            << " -1  > 1? " << (n > u) << '\n';
}
$ ./a.out
 -1 == 1? false
Comparing two signed values:
 -1  < 1? true
 -1  > 1? false
Comparing signed and unsigned:
 -1  < 1? false
 -1  > 1? true
$

assign operators

opeartorsyntaxequivalent statements
assignmenta = ba = b
addition assignmenta += btemp = a + b; a = temp
subtraction assignmenta -= btemp = a - b; a = temp
multiplication assignmenta *= btemp = a * b; a = temp
division assignmenta /= btemp = a / b; a = temp
modulo assignmenta %= btemp = a % b; a = temp
bitwise AND assignmenta &= btemp = a & b; a = temp
bitwise OR assignmenta \|= btemp = a \| b; a = temp
bitwise XOR assignmenta ^= btemp = a ^ b; a = temp
bitwise left shift assignmenta <<= btemp = a << b; a = temp
bitwise right shift assignmenta >>= btemp = a >> b; a = temp

conditional operators

opeartorsyntax
conditional operatora ? b : c
#include <iostream>
int main()
{
  // simple rvalue example
  int n = 1 > 2 ? 10 : 11; // 1>2 is false, so n = 11
  // simple lvalue example
  int m = 10;
  (n == m ? n : m) = 7;                      // n == m is false, so m = 7
  std::cout << "n = " << n << "\nm = " << m; //output the result
}
$ ./a.out
n = 11
m = 7
$

priority

precedenceoperator
1a++, a--
2++a, --a
3+a, -a
!a, ~a
(type)
5a * b, a / b, a % b
6a + b, a - b
7a << b, a >> b
9a < b, a <= b, a > b, a >= b
10a == b, a != b
11a & b
12a ^ b
13a \| b
14a && b
15a \|\| b
16a ? b : c, a = b, a += b, a -= b, a *= b, a /= b, a %= b, a <<= b, a >>= b, a &= b, a ^= b, a \|= b
// Credit: E. Chen
#include <iostream>

int main()
{
  std::cout << !0 + 1 << std::endl;
  std::cout << !(0 + 1) << std::endl;

  int a = 6 % 10 / 2 + 1 % 2 >= 3 || !+4 - 9 <= -1;
  /***
     * step 1 -> int a = 6 % 10 / 2 + 1 % 2 >= 3 || ! (+4) - 9 <= (-1);
      (Unary plus and minus)
     * step 2 -> int a = 6 % 10 / 2 + 1 % 2 >= 3 || (0) - 9 <= (-1);
      (Logical NOT)
     * step 3 -> int a = (6 % 10 / 2) + (1 % 2) >= 3 || 0 - 9 <= (-1);
      (Arithmetic multiplication, division and remainder)
     * step 4 -> int a = (3 + 1) >= 3 || (0 - 9) <= (-1);
      (Arithmetic addition and substraction)
     * step 5 -> int a = (4 > 3) || (-9 <= -1);
      (Relational operators)
     * step 6 -> int a = (true || true);
      (Logical operators)
     * step 7 -> int a = true;
      (assignmnet operators)
    ***/
  std::cout << a << std::endl;

  return 0;
}

Reference: