AnswerBun.com

How to modify this C++ class to be as efficient as C code?

Stack Overflow Asked by Victor CANOZ on August 7, 2020

Today I’ve wanted to check if it is possible to write C++ code that is as efficient as C code. Because I’m working on an embedded system, I want to make sure using C++ will not impact performance too much.
So I’ve written a C code for manipulating fake GPIOs registers, as well as its C++ counterpart.

#include <stdbool.h>
#define PUSH_BUTTON_PORT 0
#define PUSH_BUTTON_PIN 4

volatile int port0_pin_dir= 0;
volatile int port0_pin_read = 0;

void inline gpio_init_input(unsigned int port, unsigned int pin)
{
    switch (port)
    {
        case 0:
            port0_pin_dir |= 1 << pin;
        break;
        case 1:
            //manage port 1 direction register...
        break;
    }
}

bool inline gpio_read(unsigned int port, unsigned int pin)
{
    switch (port)
    {
        case 0:
            return (port0_pin_read >> pin) & 1;
        case 1:
            //TODO: manage port 1 direction register...
            return 0;
    }
}

volatile bool is_pressed = 0;
int main()
{
    gpio_init_input(PUSH_BUTTON_PORT, PUSH_BUTTON_PIN);
    is_pressed = gpio_read(PUSH_BUTTON_PORT, PUSH_BUTTON_PIN);
    return 0;
}

equivalent C++ code:

volatile int port0_pin_dir = 0;
volatile int port0_pin_read = 0;

template<unsigned int PORT, unsigned int PIN>
class gpio
{
public:
    gpio()
    {
        static_assert(PORT < 2, "This chip has only 2 gpio ports");
        static_assert(PIN < 32, "This pins has 32 pins per port");
    }

    void init_input()
    {
        switch (PORT)
        {
            case 0:
                port0_pin_dir |= 1 << PIN;
            break;
            case 1:
                //TODO: manage port 1 direction register...
            break;
        }
    }

    bool read()
    {
        switch (PORT)
        {
            case 0:
                return (port0_pin_read >> PIN) & 1;
            case 1:
                //TODO: manage port 1 direction register...
                return 0;
        }
        
    }
};

volatile bool is_pressed = false;
int main()
{
    gpio<0,4> push_button;
    push_button.init_input();
    is_pressed = push_button.read();
    return 0;
}

If I enable -O3 optimization, both source codes result in exactly the same compiler output, which is great. You can check by yourself here:
https://godbolt.org/z/P7ov8E for C++, and here https://godbolt.org/z/Kav6qb for C.

Now assume I need to iterate through the gpios to initialize a bunch of them as inputs. In C it is quite easy, and I would add this to the main() function:

for (int i =0; i<10;i++)
{
    gpio_init_input(PUSH_BUTTON_PORT, i);
}

For the C++ version, I had to re-write the class because it was a templated class, and you can’t easily iterate through multiples types of a class.

So here is the new C++ code:

volatile int port0_pin_dir = 0;
volatile int port0_pin_read = 0;

class gpio
{
    unsigned int port;
    unsigned int pin;
public:
    gpio(unsigned int port, unsigned int pin)
    {
        port = port;
        pin = pin;
    }

    void init_input()
    {
        switch (port)
        {
            case 0:
                port0_pin_dir |= 1 << pin;
            break;
            case 1:
                //TODO: manage port 1 direction register...
            break;
        }
    }

    bool read()
    {
        switch (port)
        {
            case 0:
                return (port0_pin_read >> pin) & 1;
            case 1:
                //TODO: manage port 1 direction register...
                return 0;
        }
        
    }
};

volatile bool is_pressed = false;
int main()
{
    gpio push_button(0,4);
    push_button.init_input();
    is_pressed = push_button.read();

    for (int i =0; i<10;i++)
    {
        gpio pin(0,i);
        pin.init_input();
    }

    return 0;
}

As you can see here https://godbolt.org/z/dzMnds for the C++ version and here https://godbolt.org/z/4czfKx for the C version, the C++ compiler output is about 25% bigger than the C counterpart.

So is their a way of using a C++ class in this case without compromising efficiency (over C)?

One Answer

The following change helps

class gpio
{
    const unsigned int port;
    const unsigned int pin;
public:
    gpio(unsigned int port, unsigned int pin) : port(port), pin(pin)
    {
    }

By declaring the member variables as const (and consequently using an initialisation list in the constructor) it helps the compiler optimise their use.

I'm no expert on reading assembly, but that seems to make the two programs compile to equivalent code.

Correct answer by john on August 7, 2020

Add your own answers!

Related Questions

Java Double.valueOf

2  Asked on November 4, 2021 by fabiitch

   

How can I write an alias of Raku regexes?

1  Asked on November 4, 2021 by lovetomato

     

What is a niebloid?

2  Asked on November 4, 2021 by armin-montigny

   

Is Execution time or Result time correct?

4  Asked on November 4, 2021 by snapo

 

BigInt inconsistencies in PowerShell and C#

4  Asked on November 4, 2021 by nico-nekoru

       

Why is the ‘simplified’ code not vectorized

1  Asked on November 4, 2021 by david-frank

         

Ask a Question

Get help from others!

© 2022 AnswerBun.com. All rights reserved. Sites we Love: PCI Database, MenuIva, UKBizDB, Menu Kuliner, Sharing RPP, SolveDir