⚙️Tutorial: C++ Part 3

C/C++ Tutorial 3 — Finishing the C of C++
Section titled “C/C++ Tutorial 3 — Finishing the C of C++”This tutorial will guide you through more advanced foundational concepts of the C of C++ for edge programming, including platform-specific types, data structures, bitwise operations, exceptions and interrupts. I am purposefully avoiding classes at this point, but much of the code in this section also applies to the use of classes.
Work through the 10 exercises below. Each question includes a sample solution and an explanation in the associated video. Please try this yourself first before watching the video.
Good luck!
Question 1: Platform-Specific Types and sizeof
Section titled “Question 1: Platform-Specific Types and sizeof”In embedded and edge programming, it is crucial to manage memory efficiently and to ensure your data types have a predictable size regardless of the system they are running on. The standard integer types like int can vary in size (e.g., 2, 4, or 8 bytes) depending on the compiler and the system architecture (e.g., 16-bit vs. 64-bit). The <cstdint> header provides platform-independent types with a guaranteed size.
Write a C++ program that includes the <cstdint> header and declares a uint8_t variable. Use the sizeof operator to print the size in bytes of both a standard int and the uint8_t type on your platform.
Question 2: The goto Statement
Section titled “Question 2: The goto Statement”The goto statement performs an unconditional jump to a labeled point in the code. While its use is generally discouraged in modern programming due to its ability to create complex and hard-to-read code, understanding its basic function is still important for working with legacy code and in certain low-level contexts.
Write a program that uses an if statement and a goto statement to skip printing a message if a variable’s value is 5. Use a label named skip_print:
This tutorial question is a chance for you to get goto out of your system so that you never have to use it again!
Question 3: Structs
Section titled “Question 3: Structs”A struct (short for structure) is a user-defined data type that groups together variables of different data types under a single name. Structs are a fundamental concept in C and C++ for creating logical records of data. They are commonly used in embedded systems to represent hardware registers, data packets, or sensor readings where related information needs to be bundled together. A key difference from classes is that structs typically do not contain methods, focusing purely on data aggregation. This is largely because structs are available in C and C++ remains somewhat backward compatible.
Write a C++ program that defines a struct named SensorData to represent a reading from a temperature and humidity sensor. The struct should have two members: a float for temperature and an int for humidity. Declare a variable of this struct type, assign values to its members, and then print the sensor readings to the console.
Question 4: Unions
Section titled “Question 4: Unions”A union is a special data structure that allows you to store different data types in the same memory location. The size of a union is determined by the size of its largest member. This is a powerful tool for memory optimisation, especially in memory-constrained environments like edge devices, where you know that only one of the members will be in use at a time. It is incumbent on the programmer to remember which data type is in use, which is why you have to be very careful with this structure.
Write a program that defines a union that can hold either an int or a float. Assign a value to the int member and print it, then assign a value to the float member and print that. Observe how accessing the int member after assigning the float member leads to an invalid value.
Question 5 (a): Enumerations (enum)
Section titled “Question 5 (a): Enumerations (enum)”An enumeration or enum is a user-defined data type that consists of a set of named integer constants. This makes your code more readable and self-documenting by allowing you to use meaningful names instead of “magic numbers.” Enumerations are particularly useful in embedded systems for representing states, modes, or specific options (e.g., register names and values).
Building on a similar question from Tutorial 2, write a program that defines an enumeration for the days of the week. Declare a variable of this enum type, assign it a value, and then use a switch statement to print a message based on the chosen day. The message should only indicate: whether it is a “weekday”, or the “weekend day”, or an “invalid day.” Write the code to be concise.
Question 5 (b) : Constraining Function Parameters with enum
Section titled “Question 5 (b) : Constraining Function Parameters with enum”A key benefit of using an enumeration is that it can constrain the possible values for a function parameter. This improves type safety and makes your code more robust by preventing a function from being called with an invalid or nonsensical integer value.
Write a C++ program that uses the Day enumeration from the previous question. Define a function named isWeekday that takes a Day enumeration as a parameter and returns a boolean value (true or false) to indicate if it is a weekday.
Test if you can send an int to the function in place of the Day enumeration.
Question 6: Bitwise Operators (AND and OR)
Section titled “Question 6: Bitwise Operators (AND and OR)”Bitwise operators perform operations on individual bits of an integer. The bitwise AND (&) and bitwise OR (|) operators are fundamental for tasks like setting, clearing, or checking specific flags in a register, which is a common task in microcontroller programming.
Write a program that uses bitwise operators to manipulate a single integer. Start with a uint8_t flags with the value 5, then use the | operator to set the fourth bit from the right (which has a magnitude of 8) and use the & operator to check if that bit is set. Display the final value of flags using the display function.
Use the following code to display your bit values and to start your program:
#include<iostream>#include<bitset>#include<sstream>#include<iomanip>#include <cstdint>using namespace std;
// display the actual bits of an unsigned 8-bit valuestring display(uint8_t a) { stringstream ss; ss << setw(3) << (int)a << "(" << bitset<8>(a) << ")"; return ss.str();}
int main() { uint8_t flags = 5; // Binary: 00000101 cout << "Initially, the flags value is " << display(flags) << endl;
// place your Question 6 code here!
return 0;}Question 7: Bitwise Shift Operators
Section titled “Question 7: Bitwise Shift Operators”Bitwise shift operators (<< and >>) move all the bits of an integer to the left or right. A left shift (<<) is equivalent to multiplying by a power of two, while a right shift (>>) is equivalent to an integer division by a power of two. These operations are often faster and more efficient than standard multiplication or division, which is a critical consideration for performance in embedded systems.
Write a program that uses left and right bit shift operators to perform multiplication and division by powers of two on a uint8_t a = 10 and a uint8_t b = 40.
Use the display function from the previous question to help you understand the shift operations.
Start with the following code segment:
#include<iostream>#include<bitset>#include<sstream>#include<iomanip>#include <cstdint>using namespace std;
string display(uint8_t a) { stringstream ss; ss << setw(3) << (int)a << "(" << bitset<8>(a) << ")"; return ss.str();}
int main() { uint8_t a = 10; uint8_t b = 40; cout << "a =" << display(a) << " and b =" << display(b) << endl;
// Left shift for multiplication (multiply a by 2 to get 20)
// Right shift for division (divide b by 4 to get 10)
return 0;}Question 8: Recursion
Section titled “Question 8: Recursion”Recursion is a powerful programming technique where a function calls itself to solve a smaller version of the same problem. This continues until a simple “base case” is reached, at which point the function unwinds and returns a result. Recursion is often used to solve problems that can be broken down into smaller, self-similar sub-problems, such as traversing tree structures or calculating mathematical sequences.
Recursion is useful in embedded systems and resource-constrained environments because it allows complex problems (like tree traversal, divide-and-conquer algorithms, or parsing) to be expressed with minimal code size, reducing program memory usage. Instead of writing large, repetitive loops or managing explicit stacks, recursion lets the program reuse the call stack to handle sub-problems elegantly.
That said, recursion must be used with care in embedded systems, since excessive depth can quickly consume limited stack memory. When applied appropriately (e.g., in shallow, predictable recursion), it provides compact, maintainable, and efficient solutions.
Write a C++ program that uses a recursive function to calculate the factorial of a given number. The factorial of a non-negative integer n is the product of all positive integers less than or equal to n. (e.g., 5=5×4×3×2×1=120).
Question 9: Exception Handling (try and catch)
Section titled “Question 9: Exception Handling (try and catch)”Exception handling is a mechanism in C++ that provides a structured way to handle unexpected or exceptional situations that arise during program execution, such as division by zero or an invalid file operation. Instead of the program crashing, you can use the try-catch block to gracefully manage the error. The code that might throw an exception is placed in the try block, and the code that handles the exception is placed in the catch block.
Write a C++ program that defines a function to perform division. Use a try-catch block to handle the case where the divisor is zero, preventing a runtime error. Remember to include the stdexcept header file.
Question 10: Interrupts (Simulation)
Section titled “Question 10: Interrupts (Simulation)”In edge computing and embedded systems, interrupts are hardware signals that temporarily suspend the normal execution of a program to handle an important event. This is much more efficient than polling, where the program constantly checks a sensor or device for a change. Interrupts ensure that time-critical tasks, like responding to a button press or an incoming data packet, are handled immediately.
Write a C++ program that simulates a hardware interrupt using a global flag. The main function will be busy doing a repetitive task, and a separate function will act as the Interrupt Service Routine (ISR) that gets “called” when the flag is set.
The video solutions for these questions are available in the next section.
Solutions
Section titled “Solutions”Here are the video solutions — please do not watch these solutions without having attempted the questions first. Please note that these solutions are somewhat warts and all in that I make errors and correct them live without edits.
Alternatively, you can view the video directly on YouTube: https://www.youtube.com/watch?v=jbbmatC1HxQ
© 2026 Derek Molloy, Dublin City University. All rights reserved.