Сегодня я хотел проверить, можно ли написать код на C ++, столь же эффективный, как код C. Поскольку я работаю над встроенной системой, я хочу убедиться, что использование C ++ не слишком сильно повлияет на производительность. Итак, я написал код C для управления поддельными регистрами GP IOs, а также его аналог на C ++.
#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;
}
эквивалентный код C ++:
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;
}
Если я включить оптимизацию -O3, оба исходных кода дают точно такой же вывод компилятора, и это здорово. Вы можете проверить самостоятельно здесь: https://godbolt.org/z/P7ov8E для C ++, а здесь https://godbolt.org/z/Kav6qb для C.
Теперь предположим, что мне нужно выполнить итерацию через gp ios для инициализации группы из них в качестве входных. В C это довольно просто, и я бы добавил это к функции main ():
for (int i =0; i<10;i++)
{
gpio_init_input(PUSH_BUTTON_PORT, i);
}
Для версии C ++ мне пришлось переписать класс, потому что это был шаблонный класс, и вы не можете легко перебирать несколько типов класса.
Итак, вот новый код C ++:
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;
}
Как вы можете видеть здесь https://godbolt.org/z/dzMnds для версии C ++ и здесь https://godbolt.org/z/4czfKx для версии C, вывод компилятора C ++ примерно на 25% больше, чем у C аналога.
Так это их путь использования класса C ++ в этом случае без ущерба для эффективности (более C)?