Arm Community
Arm Community
  • Site
  • User
  • Site
  • Search
  • User
Arm Community blogs
Arm Community blogs
Tools, Software and IDEs blog How C++11/14 can improve readability without affecting performance
  • Blogs
  • Mentions
  • Sub-Groups
  • Tags
  • Jump...
  • Cancel
More blogs in Arm Community blogs
  • AI blog

  • Announcements

  • Architectures and Processors blog

  • Automotive blog

  • Embedded and Microcontrollers blog

  • Internet of Things (IoT) blog

  • Laptops and Desktops blog

  • Mobile, Graphics, and Gaming blog

  • Operating Systems blog

  • Servers and Cloud Computing blog

  • SoC Design and Simulation blog

  • Tools, Software and IDEs blog

Tags
  • ds-5
  • C++
  • compiler
  • armcc
  • development_tool_sw
  • armclang
  • c++11
  • c++14
Actions
  • RSS
  • More
  • Cancel
Related blog posts
Related forum threads

How C++11/14 can improve readability without affecting performance

Stefano Cadario
Stefano Cadario
June 19, 2015
5 minute read time.

Often we hear embedded software engineers avoiding the usage of C++ because of being scared by potential performance hit or code size explosions. Even though some features of C++ can have significant impact on the performance and code size, it would be a mistake to exclude the usage of the language completely because of this.

In this article I want to show a few additions to the C++11 and C++14 standards which can improve the readability of your code but won’t affect the performance thus can be used even with the smallest Cortex-M0+ core.

ARM Compiler 5 supports C++11 whereas ARM Compiler 6 supports both C++11 and the most recent C++14 (refer to documentation for details). If not specified, ARM Compiler 6 assumes C++03 as a standard so you need to use the command line options --std=c++11 or --std=c++14 to be able to use the newer standards. If you want to enforce the conformance to a specific standard you can use the command line option --pedantic-errors: armclang would generate an error in case you are using extension or features of the standard.

Constexpr

The constexpr keyword has been introduced with C++11 but C++14 removed a few constraints making this functionality even more powerful. When a function is declared as constexpr, the compiler will know that the result of that function can be evaluated at compile time and it can be used accordingly.

Let’s assume we want to create a static array based on the number of bits set in a word; with C++03 we would have written something similar to the following code:


const int my_word = 0xFEF1; // bit mask

int *my_array;

int number_of_bits(int word) {
    int count=0;
    while(word) {
        count += word & 0x1;
        word >>= 1;
    }
    return count;
}
...

my_array = (int*)malloc(sizeof(int)*number_of_bits(my_word));
...










With C++14 is possible to calculate this in a function and the result is available at compile time. The code can be transformed as:

const int my_word = 0xFEF1; // bit mask

constexpr int number_of_bits(int word) {
    int count=0;
    while(word) {
          count += word & 0x1;
          word >>= 1;
    }
    return count;
}


int my_array[number_of_bits(word)];











Because the function is evaluated at compile time, the compiler can instantiate the array on the stack saving the call to malloc() at run-time: readability and performance have been improved at the same time!


Binary literals

Often in our applications, we need to use bit masks or perform bit operations: How many times did we write code similar to the following?

if (x & 0x20) { // 0010 0000
 ...
}














What does 0x20 mean in this code? For an expert programmer this is clearly checking if the sixth LSB bit of x is set but it might be getting trickier with more complex bit masks. C++14 makes this even more clear. In the latest version of the standard C++14 it is possible to define binary literals, making the specification of bit masks even clearer:

if (x & 0b0010’0000) {
...
}














As you can see from the example, not only can we specify the bitmask directly but we can also use ' as a digits separator to enhance readability even further. The generated assembly code is the same but the source is easier to understand.

Range-based for loop

Most modern languages like Python and C# support range-based loops; this doesn’t add more power to the language but it improves readability of the resulting code.

This functionality has been added to C++11 and it’s now possible to use range-based loops directly in your existing code.

Let’s take a look at an example:

int my_array[] = {1, 2, 3, 4, 5};
int sum_array(void) {
    int sum = 0;
    for (int i=0; i<5; i++) {
          sum += my_array[i];
      }
    return sum;
}














This can be re-written to

Int my_array[] = {1, 2, 3, 4, 5};
int sum_array(void) {
  int sum = 0;
  for (auto value : my_array) {
    sum += value;
    return sum;
  }
}













The code reads better now and we also removed the size of the array from the for loop which is potential source of bugs (we need to update it if we add a new element for example).


The range-based for loop works with any type with begin() and end() function defined so that we can apply the same technique with std::vector:


int sum_array(std::vector<int> array) {
    int sum = 0;
    for (auto &value : array) {
        sum += value;
    }
    return sum;
}















In this case the improvements in terms of readability are even better and, as a result, the code is easier to understand and maintain.


Null pointer constant

Since the beginning of the C standard, we have used NULL to check the validity of a pointer. This led to confusion in C++ because NULL is equivalent to 0.

Let’s assume we have two functions with the same name and different arguments:


Log_value(int value); // first function
Log_value(char *value); // second function















In C++, the following code has an unexpected effect from the developer's point of view.


Log_value(NULL); // will call the first function















Infact, by using NULL we expect the second function to be called but, because NULL is equal to 0, the first function will be called instead.


In C++11 the keyword nullptr has been introduced and should be used instead of NULL, so that we can easily avoid this ambiguity:


Log_value(nullptr); // will call the second function

In this case, the second function is correctly called with an explicit null pointer value.

Summary

We have seen a few functionalities of C++11 and C++14 which can be used without worrying about performance and that can enhance the readability of your code. This article covers just a few of them, you can find more information on Wikipedia (C++11 - Wikipedia, the free encyclopedia and C++14 - Wikipedia, the free encyclopedia) and on Standard C++11 and Standard C++14.

I hope you found these information useful and you can soon start to use some of the functionalities in your code base. As mentioned at the beginning, ARM Compiler 6 supports C++11 and C++14. If you still don’t have DS-5, download a free 30-day evaluation of Ultimate Edition to get started.

Feel free to post any questions or comments below.

Ciao,

Stefano

Anonymous
Tools, Software and IDEs blog
  • Python on Arm: 2025 Update

    Diego Russo
    Diego Russo
    Python powers applications across Machine Learning (ML), automation, data science, DevOps, web development, and developer tooling.
    • August 21, 2025
  • Product update: Arm Development Studio 2025.0 now available

    Stephen Theobald
    Stephen Theobald
    Arm Development Studio 2025.0 now available with Arm Toolchain for Embedded Professional.
    • July 18, 2025
  • GCC 15: Continuously Improving

    Tamar Christina
    Tamar Christina
    GCC 15 brings major Arm optimizations: enhanced vectorization, FP8 support, Neoverse tuning, and 3–5% performance gains on SPEC CPU 2017.
    • June 26, 2025