Da C++ Code

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.

1 Like

@profezzorn Where was this when I was trying to remember college code class stuff? :innocent::+1::rofl:

Thanks and yes keep the topics going. :+1:

It’s very cool you’ve taken the time to spill some brain out for us.
May I request/suggest that actual ProffieOS code be used as some of the examples?
Like the switch case could exemplify SB_Effect or something.
This would show actual use case, which I personally would find helpful for something like
for (Effect* e = all_effects; e; e = e->next_) {

The examples are created to be as simple as humanly possible.
I want people to read this and feel like “ok that was easy”, and I think using real-world examples would slow things down.

Besides, I think it’s important to discuss pointers before tackling the example you posted, and that will be in an upcoming post…

That’s precisely what I was referring to. Looking forward to it. Thanks.

volatile mutable function pointer which returns a pointer to an int and takes in a function pointer which returns an int and takes in an int and an int. :sweat_smile:

volatile mutable int *(*member)(int (*)(int), int);

At least <fuctional> has slightly more readable syntax.

Silliness aside, pointers aren’t all that complicated. For anyone new to this stuff I think with Fredriks next post that’ll become pretty clear.