(2) cpp imperative programming

34
1 Nico Ludwig (@ersatzteilchen) (2) Basics of the C++ Programming Language

Transcript of (2) cpp imperative programming

1

Nico Ludwig (@ersatzteilchen)

(2) Basics of the C++ Programming Language

2

TOC● (2) Basics of the C++ Programming Language

– Imperative Programming

– Style and Conventions

– Constants

– Fundamental Types

– Console Basics

– Operators, Precedence, Associativity and Evaluation Order

– Control Structures and Blocks

● Sources:

– Bruce Eckel, Thinking in C++ Vol I

– Bjarne Stroustrup, The C++ Programming Language

3

Code Snippets● Hence we'll begin using code snippets (or simply called "snippets") as examples, i.e. no surrounding main() function etc.!

● If a snippet produces command line output, it will occasionally be shown in the code with the "// >"-notation in green color.

– In C++ a line starting with two slashes "//" is a C++-comment. We'll discuss those in one of the upcoming slides.

● We use colors in the snippets to highlight elements in the code: brown for text, blue for keywords and green for comments.

● Sometimes the #include directives will be left away, esp. if we can anticipate their inclusion from the code.

● In the end no fully runnable program code, but snippets will be shown in upcoming lectures!

// Main.cpp#include <iostream>

void main(){

std::cout<<"Hello World!"<<std::endl;}

#include <iostream>std::cout<<"Hello World!"<<std::endl;

#include <iostream>std::cout<<"Hello World!"<<std::endl;// >Hello World!

#include <iostream>std::cout<<"Hello World!"<<std::endl;

std::cout<<"Hello World!"<<std::endl;// >Hello World!

#include <iostream>std::cout<<"Hello World!"<<std::endl;// >Hello World!

● An important thing to keep in mind is that the execution of a C++ program starts in the free function main(). - Hence we accept that we will leave the explicit definition of main() away in the code examples of this course.● There can be only one main()-function in a C++-

application.

4

C++ Syntax Cornerstones – Part I – Imperative Elements● We'll begin by discussing imperative programming in C++.

– Imperative programming: writing programs with statements being executed sequentially to change the state of the program.

● Imperative programming includes following elements in general:

– Variables (hold the state of the program)

– Statements (executable instructions, which typically change the state (i.e. the contents of variables) of the program)

– Branches (execute statements depending an a condition)

– Loops (execute statements repeatedly)

– Input and output (communicate with the "world outside of the program" (the user, the file system or a network))

● These elements are present in C++ as well:

– Syntax elements: expressions, statements, blocks. They can be freely formatted.

● Statements and blocks are executed sequentially.

● Blocks group statements, esp. for branching and loops.

– The order of execution in expressions is not defined in C++!

– Input and output is implemented with special functions and objects.

if (answerIsOk){

std::cout<<"Result: "<<(3 + 4)<<std::endl;}

// Empty statement, pair of empty braces:// (We'll use this syntax in this course.)if (answerIsOk){ // pass}

// Empty statement:// (Not so good.)if (answerIsOk)

;

● Esp. the need to write semicolons to terminate statements scares C++ newbies.

5

C++ Syntax Cornerstones – Part II – Intermediate Results● Up to now we know how to "write" text on the command line from a C++ program:

● Well, it is also possible to write numbers to the command line:

● As we saw before we can also write the result of expressions to the command line:

● Here, the expression "45 * 3" is used in the calculation for two times. C++ allows storing intermediate results in variables.

– We can calculate the expression "45 * 3" and store its intermediate result in a variable named product.

– Then we can use product in further expressions to get the final result:

– As can be seen, we've defined a variable product with the keyword int and initialized it with the result of the expression "45 * 3".

● Using the keyword "int" defines a variable being of type integer. Integer variables can hold integer values of course!

● We'll discuss the concepts of keywords and types at once.

std::cout<<"Hello World!"<<std::endl;// >Hello World!

std::cout<<42<<std::endl;// >42

std::cout<<45 * 3 + 21 + 5 + 45 * 3<<std::endl;// >296

int product = 45 * 3;std::cout<<product + 21 + 5 + product<<std::endl;// >296

6

C++ Syntax Cornerstones – Part III – Keywords, Compile Time and Run Time

● C++ reserves symbols for its grammar, these symbols are called keywords.

– In upcoming snippets all keywords are written in blue color. We already saw some keywords: void, int and if.

● Syntax versus Semantics:

– These statements have similar C++-syntax, but their meaning is different: they have different semantics!

● Compile time errors versus run time errors:

– This code is not in correct C++-syntax! The compiler will reject it, issue a compile time error and abort the compilation-process.

● An important function of the C++-compiler is to check the syntax for syntax errors. Syntax errors result in compile time errors and abort compilation.

● The syntax error here: a constant literal value can not be assigned! Sounds logical...

– Both statements are ok for the compiler, but the last one behaves undefined at run time.

● The result of the division by 0 is undefined in C++! Sounds familiar...

– There can also exist link time errors in the C-family languages. We'll discuss this kind of complex matter in a future lecture.

int count = 2;

count = 2;

int zero = 0;int oddResult = 42/zero;

49 = 3 + 5;

initialization

assignment

invalid initialization

● What keywords does the audience know from any programming languages?● Uninitialized variables for experts: Uninitialized

auto locals have arbitrary values, statics (globals) have default values.

● Syntax versus semantics; what's that?● Grammar/keywords versus their meaning.

● Programming errors can occur on different "times" in development. Can anybody explain this statement?● The time during programming is often called

"design time".

7

C++ Syntax Cornerstones – Part IV – Variables● The most elementary statements are variable definitions.

– In C++, variable definitions make variables applicable in the code.

– Variables need to be typed on definition/declaration, this is called static typing.

● A defined variable has a value/state and consumes memory.

– The compound of a variable's name and its value/state/memory is called object.

● Besides definition, variables can be initialized, assigned to and declared

– Initialization gives initial values to a variable.

– Assignment sets a variable to a new value.

– Declaration makes a name known in the code.

● A declaration of a name can be repeated in the code, definitions cannot!

int age = 19; int age(19); int age = {19}; // Initialization

age = 25; // assignment

extern int anotherAge; // variable declaration

double width = 32.8;

C++11 – type inferenceauto age = 19;

C++11 – uniformed initializersint age{19};

● What is the difference between declaration and definition?● In principle there is only one difference: we can

have multiple declarations of the same entity in the same translation unit, but no multiple definitions. Each entity can be defined only once, this is called one definition rule (ODR) in C++

● A definition of a symbol implies the declaration of that symbol in C++.

● In C++ multiple variables of the same type can be defined/declared in one statement.

● After declaration variables are referenced just by their name (prefixes or sigils (like the '$' sigil) as found in scripting languages are not used).

8

C++ Syntax Cornerstones – Part V – Scopes● The region, in which a symbol has a meaning and can be used is called scope.

– I.e. functions and variables have a scope.

– C++ limits the scope of symbols by the positioning in the code and by bracing.

● Local variables have the scope of the surrounding function.

– The definition of a local symbol must be unique in the same scope:

– The definition of a local variable can be overlapped by a definition in a sub scope.

● Sub scopes are constructed as a block of code enclosed in braces.

● Overlapping definitions should be avoided!

int x = 23;{

int x = 50; // Ok! Overlaps x.std::cout<<x<<std::endl;// >50

}std::cout<<x<<std::endl;// >23

int x = 23;int x = 50; // Invalid! Redefinition of x.

● What is a scope?● A scope defines an area of code, in which a

variable has certain meaning.● Other example: The scope of a variable in

JavaScript is the scope of the function, in which the variable is defined. - There are no other sub scopes (e.g. curly braces).

9

C++ Syntax Cornerstones – Part VI – Types● Fundamental types: builtin types, whose objects can be created with literals.

– We already know the fundamental type int. int variables can be created with integer literals:

– We'll learn C++' fundamental types in short.

● Compound types, i.e. complex types built from other types:

– 1. Fundamental types with qualifier: pointers and arrays.

– 2. User defined types (UDTs): enums, structs, bit-fields, unions, classes and typedefs

– 3. Functions

● Other tools for types:

– C/V-qualifiers: const/volatile

– The sizes of types and objects can be retrieved with the sizeof-operator.

– (Compound types can be aliased with typedefs, which makes them UDTs.)

● Type conversion:

– Standard conversions are done implicitly.

– Explicit conversions are done with explicit cast operators.

// Standard (implicit) conversion:int i = 2.78;

// Explicit conversion with casts:int i = (int)2.78;int j = int(2.78);int k = static_cast<int>(2.78);

int value = 23;

● What are fundamental types?● These types are integrated into C++ (as keywords).● What is a literal?

● A literal is a value of specific type that can be written out in source code directly.

● In a sense a literal is the opposite of a symbol.● In C++11 we can define user defined literals.

● What is "const" and "volatile"?● If an object is declared volatile, the C/C++ compiler assumes

that its value could change anytime by any thread of execution. - Accessing a volatile variable is interpreted as direct memory read/write w/o caching.

● In which "unit" does the sizeof operator return its result?● In std::size_t, a std::size_t of value 1 represents the

sizeof(char). The type std::size_t is defined in <cstddef>.● The operator sizeof can be used for variables and types. In the

latter form we are required to write the type argument for sizeof in parentheses.

● Type conversion:● A conversion from a smaller type to a greater (widening

conversion) as well as from a greater to a smaller type works implicitly, if the types are "related" (int -> char). So in C++ type conversions are not type safe!

● A conversion between "unrelated" types (int* -> int) must be done explicitly.

10

C++ Syntax Cornerstones – Part VII – Identifiers and Comments● C++ uses case sensitive identifiers, we have to obey common conventions.

– aValue is not the same identifier as aVaLuE!

– We've to use a common notation (e.g. camelCase or PascalCase) as convention!

– Umlauts and special characters (save the underscore) are not allowed in identifiers!

– Compile time constants are often named with ALL_UPPER_CASE_UNDERSCORE.

– C++ keywords and special identifier-patterns mustn't be used as identifiers.

● Identifiers mustn't start with underscore+upper-case-letter or contain a double-underscore.

– Free identifiers can be put into namespaces.

● Comments allow to write all kinds of human readable annotations into the code, without introducing syntax errors.

– Comments can be applied everywhere in code. We should exploit comments!

– (Virtually, comments are not that good, because they never change!)

● We as programmers have to change comments along with changes in the code.

– Better than comments is self describing code!

– Semantically, comments are ignored by the compiler.

– Technically, comments are replaced by whitespaces before the preprocessing phase.

/* commented */ // commented

int _Eva = 34; // Invalid! bool may__be = true; // Invalid!

● What is a block?● C++ code is "block-oriented". I.e. code is written in blocks. -> Please indent blocks!● More precisely a block consists of statements.● In control structures a block acts like a single statement.● We can use whitespaces everywhere in our blocks, statements and expressions.

● What is a whitespace?● Comments

● Esp. programming newbies should use comments very often to remember what the code does. Later in the life as programmer, produced code should document itself.

● Multiline comments act like a set of parentheses that enclose the commented text. Comments will be converted into whitespaces before the preprocessing phase starts.

● Prefer: Single line comments concern only one line.● Avoid multiline comments as they can not be cascaded. The first occurrence of /* is always

matched with the first occurrence of */.● All identifiers are case sensitive.

● What's an identifier?● Use PascalCase for types and public type members.● Private and local identifiers should be written in camelCase.

● The special underscore rules are used for (future) reserved names in C/C++.● What makes up a variable?

● A name, a type and a value.● Variable names should not be short names like in maths, rather use meaningful names. -

Alas in the examples of this course often short variable names will be used.● Declaration, definition and initialization.

● What's that?● A declaration introduces a symbol; a declaration of a symbol can be repeated in code.● What is a symbol?

● Symbols are identifiers with a special meaning in code (e.g. identifiers of variables, constants or functions).

● A definition reserves memory for a value of a symbol; a definition of a symbol mustn't be repeated in code!

● An assignment sets the value of a symbol of a variable; assignments of variables can be repeated in the code.

● An initialization combines the definition of a symbol with the assignment of a value. An initialization of a symbol mustn't be repeated in the code!

11

Constants – Part I● Sometimes, we have to deal with values that never change!

● 1. We can use constant values, e.g. the value 3.14 (pi) calculating a circle's area:

– Will we remember the meaning of 3.14? Such values are called magic numbers.

– Magic numbers should be avoided, as we could forget their meaning!

● 2. We can use a variable for pi to give the value a memorable name:

– But we can not prevent programmers from assigning to variables!

● But we can solve these problems with the introduction of constants.

// The double variable PI:double PI = 3.14;

PI = 4; // Ouch! Changes the meaning of PI!

double a = r * r * 3.14;

// Better memorable, eh?double a = r * r * PI;

12

Constants – Part II● 3. We've already discussed const-qualified types, which solve this problem:

– Such objects that can not be modified are called constants.

● Constants prevent us doing coding errors and provide self documentation.

– They are not modifiable and they replace magic numbers perfectly.

● Facts about constants in C++:

– Compile time constants are often named with ALL_UPPER_CASE_UNDERSCORE.

– Run time constants can also be defined. A mighty feature!

– Integral constants can also be defined with enums.

– The "constness" of user defined types can be controlled in a fine grained manner.

● But it can be a complex job, as this is also a mighty feature!

PI = 4; // Invalid! PI is a constant, not a variable!

// Constant double (compile time constant) PI:const double PI = 3.14;

// This line remains valid:double a = r * r * PI;

// a as run time constant:const double a = r * r * PI;

const double SPEED_OF_LIGHT_KM_S = 300000;

13

C++ Fundamental Integral Datatypes● int, long, short, char/wchar_t and bool

● Integral types default to be signed, can be marked to be unsigned with the keyword unsigned.

● Signed types generally use the two's complement representation in memory.

– So the range of the value domain is broken into a negative and a positive wing.

– The 0 (zero) counts as positive value.

● Literals and sizes:

– char {'A', 65, 0x41, 0101}; 1 = sizeof(char), at least 1B underneath

– int/short {42, -0x2A, 052}; sizeof(char) ≤ sizeof(short), at least 2B ≤ sizeof(int)

– long {42L, -0x2al, 052L}; sizeof(int) ≤ sizeof(long), at least 4B

– wchar_t {L'A', 65, 0x41, 0101}; sizeof(char) ≤ sizeof(wchar_t) ≤ sizeof(long)

– bool {true, false; falsy: 0; truthy: 42, -0x2A, 052}; 1 ≤ sizeof(bool) ≤ sizeof(long)

● C99's <stdint.h> defines integer types of guaranteed size, <inttypes.h> defines integer types of specific size and<stdbool.h> defines an explicit boolean type.

// Definition and initialization of an int:int numberOfEntries = 16;

C++11 – new char typeschar16_t c1 = u'c';char32_t c2 = U'c';

C++11 – min. 64b integerlong long x = 24LL;

C++14 – binary integerliteralauto x = 0b00101001;

C++14 – digit separatorsint x = 1'000'000;

● What are "integral" types?● What is the two's complement?● We should always use int as our default integral type.

● The unsigned is needed, if we have to deal with raw memory or bit-fields.

● Never use unsigned as it is a source of nasty bugs in innocent looking code! - We'll revisit this topic in a later lecture.

● Never use short or char as long as there is no compelling reason. - They will be automatically promoted to int in all expressions, safe sizeof or taking their address.

● We should never use long, if we think int is too small. Because in this case long is mostly also becoming too small. - Better introduce a user defined type. - "int is the biggest (integral) type that is efficient" (John Lakos).

● Literals of type long should always be written with an upper case L to avoid "optical illusions", because a lower case l could be confused with the digit 1 depending on the editor's font.

● C++11 officially introduced long long with at least 8B for really large numbers, but we have to think twice if we want to use it (see above).

● wchar_t literals need to start with an upper case L!

14

C++ Fundamental Floating Point Datatypes● double, float and long double

– Always signed.

● Generally represented as described in IEEE 754 (here single (float)).

● Literals and sizes:

– sizeof(float) ≤ sizeof(double) ≤ sizeof(long double)

– double {12.3, .5 (0.5) , 10. (10.0), 123E-1}; often 8B -> exp. 10b, mts. 53b, prc. 15-16 digits

– float {12.3F, .5f, 10.f, 123E-1f}; often 4B -> exp. 8b, mts. 23b, prc. 6-8 digits

– long double {12.3L, 123E-1L}; -> 10B with exp. 15b, mts. 64b, prc. 19-20 digits

● Leading zeros can not be used in floating point literals!

mmmmmmmmmmmmmmmmmmmmmmm

31st: sign bit

s eeeeeeee

30th – 23th: exponent 22th - 0th: mantissa

- 23 bit -- 8 bit -

2-1 2-2 2-3 ... ... 22 21 20

// Definition and initialization of a double:double approxDistance = 35.25;

C++14 – digit separatorsdouble x = 0.000'026'7;

● What does the term "double" exactly mean?● The double precision of float, the C/C++ type float

has single precision.● A double can represent bigger and more precise

numbers than float.● Floating point types try to display rational numbers

of various precision.● Institute of Electrical and Electronics Engineers

(IEEE, pronounced as "i triple e").● We should always use double as our default

floating point type!● The hardware (FPU) is typically optimized for

doubles.● APIs for embedded systems do often not support

double precision. E.g. Open GL ES (ES for Embedded Systems) provides only float in its interfaces.

● We have to be aware that we have to use "." instead of "," in the floating point literals! -> Therefore these datatypes are called floating point datatypes!

15

Text Type: C-strings● In some examples we already saw the application of text values, e.g. to write text to the command line.

● The type, which represents text in C++, is called string, more specifically c-string.

– C-strings are represented as "strings of characters", which are arrays of chars in C++ lingo.

● Initialization, literals and literal concatenation:

The assignment of c-strings isn't defined, the function std::strcpy() must be used:

● The concepts of c-strings are simple in theory, but hard in practice! Why c-strings are hard to use:

– Esp. assignment and non-literal concatenation must be done with functions!

– C-string manipulation involves working with pointers and raw memory.

– C-strings are 0-terminated, which makes them error prone as well...

– => We'll discuss the concepts of memory, arrays and c-strings in depth in a future lecture!

char aName[] = "Arthur";

const wchar_t* anotherName = L"Ford";

// Erroneous:aName = "Marvin"; // Invalid!

// Correct: Copy "Marvin" to aName:std::strcpy(aName, "Marvin"); // Ok!

C++11 – new string literals/raw stringschar16_t s1[] = u"st";char32_t s2[] = U"st";char s3[] = u8"st";char rawString[] = R"(s\t)";char fullName[] = "Arthur " "and" " Ford"; // Concatenation of literals (also over multiple lines)

● What is an array?● Concerning the term "string" mind the German term

"Zeichenkette", which means "string of characters".● C-strings can also be represented as arrays of

wchar_t.● What is the difference between aName and

anotherName?● The contents of aName can be modified, the

contents of anotherName not. anotherName is a "real" c-string (of type const char*).

● Btw: we can not assign c-strings, because they are arrays and arrays can't be assigned.

● The expression "std::strcpy()" is a so called function-call.

● What does the prefix "std::" in front of the function name "strcpy()" mean?● Every object of the C++ standard library is contained

in the namespace std. The namespace name must be prefixed (incl. the scope operator "::") in front of the function name to find the specified function. - More on this topic in future lectures.

16

Working with the Console

● All the examples in this course will be console applications.

● Console applications make use of the OS' command line interface.

● To program console applications, we need basic knowledge about the console.

– Esp. following commands are usually required:

Action Windows Unix-like/OS X

Change directory cd <dirName> cd <dirName>

Change directory to parent cd .. cd ..

List current directory dir ls -l

Execute an application <appName>.exe ./<appName>

Execute an application with three arguments

<appName>.exe a b "x t" ./<appName> a b "x t"

17

Formatted Output to Console (STL)

● Writing messages to the console is a very important means to communicate!– #include (pronunciation: "pound include") the header file (h-file) <iostream>.

– Then the output streams std::cout and std::wcout can be used to output values.

● The operator << can be used in a chained manner to output multiple values:

● The output streams are buffered, the buffer must be flushed to console:

– To flush the stream, chain std::flush or std::endl to the output expression.

● Output can be formatted with manipulators (e.g. std::boolalpha), which can be chained as well:

– #include the h-file <iomanip> to use manipulators accepting arguments (e.g. std::setprecision()):

std::cout<<"Hello there, You know about "<<42<<"?";

// Use std::boolalpha to output boolean values as literal text:std::cout<<std::boolalpha<<(23 < 78)<<std::endl;

// Use std::fixed and std::setprecision() to output 2-digit floating point value:std::cout<<std::fixed<<std::setprecision(2)<<2.666<<std::endl;

std::cout<<"Hello there, You know about "<<42<<"?"<<std::endl;

● What is "std::wcout"?● The outputstream-operator << is often called

"inserter" or "chevrons" (developer slang) (instead of left-shift).

● The manipulator std::fixed forces a minimum numbers of digits to be printed after the period; this minimum number of digits will be set with std::setprecision(). The manipulator std::setprecision() will round a floating point value (it has no effect on integral types), the printed result depends on the precision and the rounding behavior (round-to-nearest, round-to-nearest-odd/even etc.), the platform and how the compiler does represent floating point values.● Manipulators are effective, until they are

overridden by other "competing" manipulators (e.g. std::hex and std::dec that override each other). The effectiveness is also spanning multiple statements, when used on the same stream object!

18

Formatted Input from Console (STL)

• Use std::cin and std::wcin (<iostream>) input streams to read all kinds of types.

– Before a program requires input from the user, it should prompt with an output!

– Then the input operation blocks program execution and forces user interaction.

• The operator >> can be used in a chained manner to read multiple values.

• Esp. c-strings can also be read with std::cin's member function getline().

• Both variants read c-strings up to len-1 characters and append the 0-termination.

const int len = 256;char yourName[len];int yourAge = 0;std::cin>>yourName>>yourAge;

const int len = 256;char yourName[len];std::cin.getline(yourName, len);

● What is "std::wcin"?● Prompt from lat. promptare: "to publish something".● The inputstream-operator >> is often called

"extractor" or "chevrons" (developer slang) (instead of right-shift).

19

Input from Console (STL) – Error Handling

● After reading, input streams should be failure-checked (e.g. wrong format read).– On failure the stream/buffer must be cleared and the user should be informed like so:

● On failure (std::cin.fail() will evaluate to true) we need to do following to reuse the input stream std::cin afterwards:– (1) Clear the failed bit (std::cin.clear()).

– (2) Clear the unread buffer that remained after the failure (std::cin.ignore()).

● Clear the specified number of characters or until the termination character is reached.

● With std::numeric_limits<int>::max() (<limits>) and '\n': an unlimited count of characters is read until '\n' is found.

int number = 0;std::cout<<"Enter a number"<<std::endl;std::cin>>number;if (std::cin.fail()) // E.g.: std::cin awaited an int, but somewhat different was read:{

std::cout<<"Please enter a valid number!"<<std::endl;std::cin.clear(); // (1) Clear stream status, esp. reset the fail status.std::cin.ignore(std::numeric_limits<int>::max(), '\n'); // (2) Clear buffer, esp. remove the pending newline.

}std::cout<<"You've entered the number "<<number<<"!"<<std::endl;

● If the failed bit is set, the next read operation on that stream will fail.

● If the stream is not reset and the buffer is not cleared the input stream is rendered unusable and will not accept inputs anymore.

20

Operator Notations – Arity

● Binary operators

● Unary operators

● Ternary operator

// Addition as binary operator:int sum = 2 + 3;

// Increment as unary operator:int i = 1;++i; // Increments i (the result is 2).

// The conditional operator is the only ternary operator:int i = 2;int j = 3;const char* answer = (i < j) ? "i less than j" : "i not less than j";

● What are binary operators?● These operators have an arity of two, i.e. they

have two operands.● The operator is written in between the operands

(infix notation).● Which other binary operators are known?

● What are unary operators?● These operators have one operand.● There exist prefix and postfix operators.

● Increment and decrement operators -> useful in loops!

● Apple's Swift programming language guide does explicitly suggest to use prefix increment/decrement by default, unless the specific behavior of the postfix variants is required. (This could be understood like Apple counts prefix increment/decrement as "primary operator".)

● What are ternary operators?● The decision operator ?: (sometimes we call it

"Elvis operator").

21

Operator Notations – Placement

● Prefix operators

● Postfix operators

● Infix operators

// Negation as prefix operator:bool succeeded = !failed;

// Increment as postfix operator:int result = item++;

// Addition as infix operator:int sum = 2 + 3;

22

Mathematical Operators

● Binary +, - and *, / known from elementary mathematics.

– Attention: Integer division yields an integer result!

– The result of the division by 0 is undefined.

● Unary – and + as sign-operators.

● Somewhat special: ++/-- and %.

● std::log(), std::pow(), trigonometric functions etc. in the h-file <cmath>.

● Bit operations work with integers as arguments and result in integers.

– Operators: ^ (xor), | (bitor), & (bitand), ~ (compl), <<, >>

– These operators should be used with unsigned values!

● What does that mean "integral division has an integer result"?● I.e. their results are no floating point values!

● Integral division: How to do that in a correct way?● Use casts or the correct literals on/for any of the

operands!● The division by 0 is not "not allowed" in maths,

instead it is "just" undefined.● What does the operator % do?

● This operator doesn't calculate the modulus, instead it calculates the remainder!

● Why do we need bitwise operators?

23

Logical Operators

● Used to compare values and combine boolean results.

– Comparison: ==, != (not_eq), <, >, <=, >=

– Combination: && (and), || (or), ! (not)

– Logical operators return boolean results, which are also integral results in C/C++.

● && (logical and) and || (logical or) support short circuit evaluation.

● Logical operators are applied in conditional expressions for control structures (branches and loops).

// The mathematic boolean expression a = b and c = b:

if (a == b && c == b) // Ok{ // pass}if (a && b == c) // Wrong!{ // pass}

// A typical beginner's error: the "optical illusion":if (a = 0) // (1) Oops! a == 0 was meant,{ // pass // but this is ok for the compiler! It evaluates to false} // (0) always, because 0 will be assigned to a!if (0 == a) // Better! Always write the constant left from the{ // pass // equality comparison.} if (0 = a) // Invalid! Here (1) could have been caught, as we{ // pass // can't assign a constant.}

// Sometimes assigning and checking values are performed intentionally:if (a = b) // Intentional assignment and evaluation.{ // pass // On modern compilers this yields a warning!} // The warning can be eliminated by writing an extra pair of parentheses:if ((a = b)) // Still not a good idea, but the syntax underscores{ // pass // the intention in a better way.}

● On many C/C++ compilers the shown "optical illusion" leads to a warning message. Some compilers (e.g. gcc) accept "marking" the assignment to be meant as condition by writing them into an extra pair of parentheses: if ((a = 0)) { /* pass */ }.● In Groovy this way of marking is required.● In Swift assignment expressions don't return a

value at all. With this simple rule a Swift expression like if a = 0 { /* pass */ } is a syntax error!

24

Precedence, Associativity and Order of Execution

● Precedence and precedence groups.

– As operator priority in maths, precedence is controllable with parentheses.

– Some operators have the same precedence and make up a precedence group.

● Associativity defines evaluation among expressions of the same precedence.

– Associativity is controllable with parentheses as well.

– Associativity is defined as a "direction".

● The order of execution within expressions is not defined in C/C++!

– The order of execution within expressions can't be controlled in C/C++!

int i = 0;std::cout<<i++<<" "<<i<<std::endl;// >0 1 → Could be this result ...// >0 0 → or this!

● What is precedence?● What is associativity?

● Rules of the thumb:● Binary operators are generally left associative.● Unary operators, the ternary operator and the

assignment operators are right associative.● Example: (a = (b = c)

B) = ((1 + 2)

A + 3)

● What is "order of execution"? Why is it relevant?● E.g. if we have an expression like h(g(), f()) or d() * s()

how can we know, which functions are being called first? This order of execution is undefined in C++! It is relevant to know that, because the function calls can have side effects!

● In C++ the order of execution is sequence point driven. The values of expressions are known after a sequence point was reached. E.g. sequence points are set in C++:● After the first/left operand of the operators ,(comma),

&&, || and ?:.● After a statement was executed.● After all arguments of a function call have been

evaluated.

25

Other Operators and Operator Overloading

● Assignment and combined assignment.

– Operators: =, +=, *= /= etc.

– Operators: &= (and_eq), |= (or_eq), ^= (xor_eq), <<=, >>=

● Extra operators:

– Operators: ,(comma), [], (), ?:, sizeof, new, delete and typeid

– Operators: * and &

– Operators: static_cast, const_cast, dynamic_cast and reinterpret_cast

– Operators: ., ->, .*, ->*

– Operators: ::, ::*

● C++ permits to redefine (overload) some operators for user defined types (UDTs).

– The introduction of new operators is not possible.

– Arity, placement, precedence and associativity of operators can't be modified.

int i = 12;i = i + 2; // (i = 14) Add and assign.i += 2; // (i = 16) Add-combined assignment.

● Esp. reinterpret_cast is used to get a bitwise view to data, it will be explained and used in future lectures.

● In C++, overloading of canonical operators is often required for UDTs.

● The programming language Haskell allows defining new operators and it allows modifying the precedence and associativity (together called "fixity" in Haskell) of present operators.

26

Control Structures – Expressions, Statements and Blocks

● An expression is like a mathematical term: "something, that yields a value".

● A statement is a set of expressions to take effect, it doesn't need to yield a value.

– Single statements need to be terminated with a semicolon.

● A block is a set of statements within curly braces ({}).

– C++ code is written in blocks, this is a main style feature.

● Blocks fringe type and function bodies type definitions and scopes.

– Blocks must be cascaded to code meaningful programs.

– Blocks should be indented to enhance readability!

– Use common conventions for indenting and bracing!

– In this course:

● We'll always use braces and braces are mandatory!

● In the lectures 1TBS will be used primarily.

● Blocks are also used for control structures.

– Mandatory for do-loops, try-blocks and catch-clauses.

if (true) // BSD style{

// In the block.}

if (true) { // 1TBS styleif (true) {

// In the cascaded// if-block.

}}

● Multiple statements can be written in one line, but need to be terminated with semicolons each.

● Blocks:● It is absolutely required to indent cascading blocks

to make the code readable!● Bracing styles:

● BSD (Berkley Software Distribution) style: should generally be used, when beginning programing, as it has a very good readability.

● 1TSB style: "Only true bracing style", it is used on the slides, as this style saves some lines (it is a "line-saver" style). This style is often used in Java code. It is the only style allowing to write correct JavaScript code to avoid mistakes because of semicolon insertion.

● There exist many more bracing styles, which is often a source of coding wars among programmers, therefor we need coding conventions to cool down the minds.

● Within blocks we can use a free syntax in C++, but please adhere to coding conventions.

27

Control Structures – Conditional Branching

● if/else and if/else if statements

– Execute code, if a specified condition is met.

– Conditions evaluate to bool, numeric results (int, double) also evaluate to bool!

– Can be cascaded, but combining conditions via logical operators is preferred.

– Each conditional code should be in a block!

– Alternatively use ?: expressions.

● => switch statement

– Does switch among a set of branched code blocks.

– Compares the statement's input against a set of constants.

– Jumps to a labeled case section, if the switch expression matches.

– Works only with integral values. Cannot be used with strings!

– Uses fall throughs, breaks and defaults - it is rather complicated!

● The switch statement will be avoided be used in this course!

– Good, when used with only returns instead of any breaks in the case sections.

● According to if/else:● Integers will be interpreted as bools, 0 will be interpreted as false (is "falsy"), all other values will be

evaluated as true (they are "truthy")!● We should always use blocks! Matching if/else pairs are clear to the reader when we use blocks.

This avoids the "dangling else" problem.● The operator ?: is more difficult to debug, because it does not consist of alternative statements to be

executed.● According to switch:

● Floating point values cannot be used.● In C/C++ only allowed with integral types.● In C/C++ switch statements do not need braces surrounding all cases and the default-case needs

no extra break statement.● (Opinion of [NLu]: Don't use switch! It looks temptingly simple, but is rather unstructured and can

introduce goofy bugs. Also it leads to longer function bodies. It should be used only in the most low level code.)● Here two examples: (Everything is valid C++ code!)

switch (argc) // Valid in C/C++: switch needs no braces at alldefault:

if (is_prime(argc))process_prime(argc);

elseprocess_nonprime(argc);

switch (pc) // Valid in C/C++: mix of inter-cascaded control // structures with switchcase START:

while (true) if (!lchild()) { pc = LEAF; return true;case LEAF: while (true) if (sibling()) break; else if (parent()) { pc = INNER; return true;case INNER:

; } else { pc = DONE;case DONE:

return false; } }

28

Enumerations – Part I

● C++ allows to group integral constants "thematically" into enumerations (enums).

– enums are the first user defined types (UDTs) we're going to discuss.

● An enum can be used like a fundamental type.

– The grouped constants are valid values for an enum variable:

● The constants of an enum can have explicit integral compile time constant values:

– Otherwise the constants have increasing default values starting from 0:

// Definition of the enumeration Month:enum Month { // Month constants:

JANUARY, FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY,AUGUST, SEPTEMBER, OCTOBER, NOVEMBER, DECEMBER

};

Month myBirthMonth = OCTOBER;

enum Color { // Explicit values:RED = 32, BLUE = 40 // … and so forth

};

enum Color { // Default values:RED = 0, BLUE = 1 // … and so forth

};

● It is not allowed to pass an arbitrary int value to an object of enum type. We can only assign/pass compatible enum constants to an object of enum type.● An int value can be explicitly converted into an

enum object. But if the int value does not match any of the int values backing the enum constants, the content of the resulting enum object is undefined. - Usually the non-matching int value will just be stored in an enum object that does not represent any of the enum constants.

● On the other hand enum objects are implicitly converted to the type int if required.

● The size of an enum can not be larger than sizeof(int).

29

Enumerations – Part II

● enum constants can be implicitly converted into ints:

– So, enums are very useful in switch statements!

● In the real world there often emerge issues with the scope of enum constants.

– Therefor enums are often defined in mightier UDTs (e.g. classes) to get back scopes.

– … or enums are not used at all!

– enums are not even used in the STL.

– The usage of enums will be avoided in this course.

– C++11 introduced strongly typed enumerations. They solve some problems of "ordinary" enums.

enum Color {RED = 32, BLUE = 40 // … and more

};int colorValue = RED;std::cout<<colorValue<<std::endl;// >32

Color color = RED;switch (color) { case RED: std::cout<<"Red"<<std::endl; break; case BLUE: // …}

C++11 – strongly typed enumerationsenum class Color {

RED = 32, BLUE = 40 // … and more};// Using the constant BLUE in Color's scope:Color myFavouriteColor = Color::BLUE;

30

Control Structures – Unconditional Branching

● return and throw

– Return from a function with or w/o value.

– Throw an exception, which leaves the function as well.

● labels and goto

– The unconditional jump statement.

– Do not use goto statements! Leads to "pasta oriented programming".

● When is goto used anyhow:

– On the automatic generation of code.

– For algorithms that need to run really fast.

● According goto: ● Don't use gotos in general. Exception: to escape

from the innermost loop of a couple of cascaded loops a goto may be appropriate.● We can not jump behind a declaration/

initialization of a variable:

goto lab; // Invalid!int c = 42;lab:

std::cout<<c<<std::endl;

31

Control Structures – Iteration – for Loop

● The for loop is a flexible counting head controlled loop statement.

– 1. Initialization expression or statement.

– 2. Conditional expression.

– 3. Update expression.

● Can imitate the functionality of any other loop!

● => Popular to iterate arrays by index (filling, processing and output).

– It should be said that processing arrays with for loops is risky:

● An array's first index is at 0, the last index is at "length – 1".

● If we get these bounds wrong (wrong initialization of the counter ( i) or wrong conditional expression), we could end up in an "off-by-one-error".

● Loops are executed sequentially, not in parallel (e.g. on multiple CPU cores).

// Print the numbers 1 – 5 to console:for (int i = 1; 5 >= i; ++i) {

std::cout<<i<<std::endl;}

● The for loop is flexible:● All parts of for's head are optional.

● If a counter variable is defined in for's head, this variable is only valid/known in the for block (this is the variable's scope).● How can we extend the counter variable's

scope?● What kinds of update expressions do we know?

● Arrays: The for loop can provide a counter variable that can be used as index for arrays.

● Downside of the for loop: the pieces/statements of for's definition are not executed in the order they are written, which makes it difficult to understand for beginners.

32

Control Structures – Iteration – while and do Loop

● while loops are head controlled.

● do loops are foot controlled.

– Must be used with a block!

– Useful for menus at the console.

● Normally, the update-operation of the loop condition is done in the loop's body.

● Loops are executed sequentially, not in parallel (e.g. on multiple CPU cores).

// Print the numbers 1 – 5 to console:int i = 1;while (i <= 5) {

std::cout<<i<<std::endl;++i;

}

// Print the numbers 1 – 5 to console:int i = 1;do {

std::cout<<i<<std::endl;++i;

} while (i < 5);

● In which situations is the update of the loop condition not required within the loop?● If we have a side effect in the conditional

expression in the head or foot (e.g. ++i).● If the data that is checked in the loop condition will

be somehow modified from "outside" (e.g. from different threads).

● Using only control structures w/o unconditional branching with gotos is called "structured programming".

33

Control Structures – Iteration – Loop Control

● continue – skips the current loop.

● break – leaves the next surrounding loop completely.

● goto – jumps to a label at almost any position in code.

– Can be used to leave a nested innermost loop.

● return and throw – leave a function.

34

Thank you!