5 C++ tips for C programmers

0

Over the past few years, C++ has become a more popular language to use in embedded systems than C. Don’t get me wrong, C will continue to be a dominant language for years to come, but C++ offers developers modern tools to exploit when designing more reusable, scalable, and portable code. Teams don’t just abandon C, but when they start developing new products, they embrace C++ instead. The language has evolved over time and offers many improvements over C. In this article, let’s look at five simple C++ tips that C programmers will immediately appreciate.

Tip #1 – Conditional Compilation Using Constexpr

The bane of many embedded codebases written in C is the large number of #if / #elif / #else preprocessor directives. Preprocessor directives are often used to conditionally compile code in and out of the frame. For example, if we have three different versions of hardware, we often create a macro that is used and then checked against the build configuration to determine pin assignments etc. The problem with conditional compilations using the preprocessor is that the code gets messy and sometimes quite hard to follow.

Starting with C++17, the language introduced the ability for developers to conditionally compile code using constexpr. Developers can take advantage of this compiler feature to optimize template-based code and even remove preprocessor directives that use #ifdef blocks. For example, if we had a codebase that had three different hardware configurations, we might find that our code to initialize GPIO looks like this:

cancel Gpio_Init()

{

#ifdef __MATERIAL_REV1__

// Initialize pin set #1

#elif __MATERIAL_REV2__

// Initialize pinset #2

#elif __HARDWARE_REV_3__

// Initialize pin set #3

#end if

}

The code above is configurable, but it is quite unpleasant to look at. Yes, a modern IDE will hide some of the options, but that’s just not a very elegant solution and leads to messy code. In C++, we can take advantage of the constexpr compile time optimization and write code like this:

constexpr Hardware_t HardwareRev = Hardware::Rev1

cancel Gpio_Init()

{

if constexpr (HardwareRev == Hardware::Rev1)

{

// Initialize pin set #1

}

else if constexpr (HardwareRev == Hardware::Rev2)

{

// Initialize pinset #2

}

else if constexpr(HardwareRev == Hardware::Rev3)

{

// Initialize pin set #3

}

}

When we compile the above code for Rev2, only the code for “Initialize pin set #2” makes it our executable. If we compile for Rev1, only the code for “Initialize pin set #1” turns it into an executable, and so on.

Tip #2 – Remote for Curls

A fundamental flow control mechanism in C and C++ is the for loop. The C for loop was stuck in the dark ages by not having a simplified range-based option. For example, languages ​​like Python allow a programmer to iterate over a range using syntax such as:

for x in the range (1, 5)

print(s)

In C, you have to write (depending on the C standard used of course):

for(int x = 1; x

{

printf(“%d rn”, x);

}

Starting with C++11, an additional version of the for loop has been added to make it easier to work with extended values. For example, if one wanted to write the code examples above in C++, one could now write it as follows:

int MyNums[] = {1, 2, 3, 4, 5};

for(int i: MyNums)

{

std::cout

}

At first, for a C developer, this may seem awkward; However, given how often we want to work on a range in an enum or object, the syntax is cleaner and easier to read.

Tip #3 – Use Auto

For C developers, auto is a long-obsolete language keyword. Developers used to use auto to specify a variable limited to the current scope. Auto is a storage class specifier like static, only it specifies that the storage is local and the variable should be automatically destroyed once out of scope, unlike static which allows the variable to persist.

In C++, auto can be a very useful keyword that tells the compiler to automatically assign the data type to the developer. For example, in tip #2, we had the following for loop code:

int MyNums[] = {1, 2, 3, 4, 5};

for(int i: MyNums)

{

std::cout

}

MyNums is already defined as an int, so I can let the compiler decide which type should be used for i as follows:

for(auto i : MyNums)

{

std::cout

}

At first it may seem sloppy. As a developer, shouldn’t I control my variable types? The answer is yes, but we should allow the compiler to handle types where it might save us time or where we don’t bother to specify them manually. Do we care if i is for example uint8_t, uint16_t, uint32_t and so on? Probably not. We just want something that can iterate over the range of one to five and the compiler is more than capable of deciding. Auto can also help when we change a data type. We can change it in one place without having to worry about changing anything downstream that uses it or interacts with it.

Tip #4 – The Spaceship Operator

This can sometimes be annoying when you need to write a conditional statement that checks if a value is less than, greater than, or equal to another value. Just recently, C++20 added a three-way comparison operator which can simplify readability and code. This operator is often called the “spaceship” operator because it looks like a spaceship.

Using the spaceship operator is simple. For example, if we have two variables and we want a three-factor comparison, we can write code like this:

int Var1 = Value1;

int Var2 = Value2;

auto Result = Var1 Var2;

If Var1 Var2, the result will be greater than 0. If Var 1 is equal to Var2, then the result will be 0.

Tip #5 – Get the Size of a String

Strings in C are nothing more than an array of characters with ‘