Ok, so if you read about the preprocessor, and the stuff that goes in the C++ files, then you might be ready to learn about the stuff that goes into methods and functions. (Also, I’m surprised you’ve put up with my particular style of “helping” for this long…)
Anyways, to the code…
A C++ function or method contains:
- type declarations
- static asserts
- variables
- return
- control structures
- statements
We’ve already discussed type declarations and static asserts outside of functions, and the only difference when you put them inside a function is that they are forgotten (“go out of scope”) at the end of the function.
Variables
Variables work almost exactly like in the global scope, but the memory for these variables are are allocated on the stack, and they are de-allocated when the function returns. A very common error in C++ code is to take a pointer to a variable inside a function (a “local” variable) and then try to access that pointer some time later, which is not allowed.
Return
Return statements make the function exit immediately with the specified return value. For functions which return void
no value is specified after the return statement. Example:
int five() { return 5; }
void nothing() { return; }
Control Structures
Control structures affect the order in which things are evaluated. Normally, everything is just evaluated from top to bottom, but control structures will cause the CPU to skip, loop or jump around. Some control structures are kind of obvious because the english words they are made of are basically self-explanatory, others not so much…
if-else
If-else is pretty much self-explanatory. The else part is optional. Let’s look at a few examples:
if (a == 5) return 10;
if (a == 6)
return 32;
if (a == 7) {
a = a + 1;
retun 90;
}
if (a < 10) {
if (a == 8)
return 100;
else
return 200;
} else {
return 300;
}
Note that the { } are not needed when the if
only controls one statement. When {} are used, it groups code together into larger blocks which are controlled as one unit.
while
While is also pretty simple, just repeat the code until the condition is not true anymore. Examples:
int a = 0;
while (a < 100) a = a + 1;
while (true) loop(); // runs forever
do-while
Do-while is similar to while(), but it runs the loop once before checking the condition. These two examples do the same thing:
// A
do {
stuff();
} while (something_is_true());
// B
stuff();
while (something_is_true()) {
stuff();
}
for
for
is short for “for each” or “for every”, and there are two versions of it:
for (INITIALIZER ; CONDITION; INCREMENT) STATEMENT
or
for (VARIABLE : CONTAINER) STATEMENT
The first one is fairly straightforward, and is normally used like this:
for (int i = 0; i < 10; i++) do_something_10_times();
(Note: i++ is the same as i = i + 1)
This reads as: for each in 0 to 9, set i to that number and run the loop. Although people normally just say “for i in 0 to 9” when reading code out loud.
This code is equivalent to:
int i = 0;
while (i < 10) {
do_something_10_times();
i++;
}
more generically, these are the same:
// A
for (INITIALIZER; CONDITION; INCREMENT) STATEMENT;
// B
INITIALIZER;
while (CONDITION) {
STATEMENT;
INCREMENT;
}
The other form of for loops is meant to be used to iterate over groups of things, like arrays and vectors. A proper explanation would take a little while, but let’s just say that if you have a container with begin() and end() methods, then you can use for to iterate over every value in that container. Here is an example:
std::vector<int> values;
values.push_back(7);
values.push_back(10);
int sum = 0;
for (int x : values) {
sum += x;
}
// sum will now be equal to 17
All the standard containers in std:: have begin() and end() methods, which makes this rather useful, but you can also make your own
continue
continue
will jump up to the beginning of a loop and check the condition again before running the loop again.
Example:
for (int i : some_numbers) {
if (i == 0) continue; // can't divide by zero
check_inverse(1.0 / i);
}
Not that when continue is used with a for() loop, the INCREMENT will still be executed, so the next value will be processed.
break
break is similar to continue, but exits the loop instead of jumping up to the condition.
switch-case
Switch is an if-statement on steroids, instead of just checking true/false, it will let you check several values of a single expression in one go. Example:
switch (rand() % 20) {
case 0:
// critical fail
you_die();
break;
case 1:
case 2:
case 3:
case 4:
// you miss
miss();
break;
default:
hit();
}
So in this case, we use switch() on a random number 0 to 19. 0 causes a critical fail and you die, 1, 2, 3, 4 means you miss and all other values means you score a hit.
switch statements can also be abused to create a sort of light-weight threading-like construct. ProffieOS uses this fairly regularly in some macros called BEGIN_STATE_MACHINE, END_STATE_MACHINE and YIELD. Those things are not threads, but uses switch statements to jump into code in ways that works similar to threads. I encourage interested readers to go read and understand these macros as they can be fairly enlightening.
labels / goto
C++ also allows for unstructured jumps in the code. There are some limitations, but essentially you can jump wherever within the same function, example:
void test() {
int i = 0;
goto condition;
loop:
do_something();
i++;
condition:
if (i < 10) goto loop;
}
Statements
Statements is just any basic evaluation. This include assignments and function calls. Statements can’t cause the code to loop, skip or jump around. [*] Statements are any valid expression made up of the following:
=
+=
-=
*=
/=
%=
&=
|=
^=
(assignments)&&
||
!
(logical operators)==
!=
<=
>=
<
>
(comparisons)|
&
~
^
(bitwise operators)+
-
*
/
%
(arithmetic operations)A()
(function calls)A ? B : C
(conditional evaluation)A[]
(index)*A
&A
(pointer and address)++
--
(increment/decrement).
(struct member lookup)->
(pointer dereference),
(sequence operator)(
)
(parenthesis)(TYPE)A
(type cast)- variable and function names
Note that A += B;
is basically just a convenient way to write 'A = A + B;`. The same goes for the other two-character assignment operators.
I’m not going to go over in detail what these does, and it highly depends on the types they are operating on anyways. In a future chapter I will go over some of the types used in C++, and at that time we’ll come back to discussing operators and what they do for those types.
[*] Ok, so I liked a bit. some operators, like A ? B : C
, A && B
and A || B
can skip evaluating bits of code similar to how an if statement works.