Esto es más una opinión / comentario que una respuesta.
No desea y no debería estar programando en C. C ++, cuando se usa de la manera correcta , es muy superior. (De acuerdo, debo admitir que, cuando se usa de manera incorrecta, es mucho peor que C.) Eso lo limita a los chips que tienen un compilador de C ++ (moderno), que es casi todo lo que soporta GCC, incluyendo AVR (con algunas limitaciones, filo menciona los problemas de un espacio de direcciones no uniforme), pero excluyendo casi todos los PIC (PIC32 podría ser compatible, pero todavía no he visto ningún puerto decente).
Cuando estás programando algoritmos en C / C ++, la diferencia entre las opciones que mencionas es pequeña (excepto que un chip de 8 o 16 bits tendrá una gran desventaja cuando hagas mucha aritmética de bits de 16, 32 o más) . Cuando necesite la última onza de rendimiento, probablemente necesitará usar el ensamblador (ya sea el suyo propio o el código proporcionado por el proveedor o un tercero). En ese caso, es posible que desee volver a considerar el chip que seleccionó.
Cuando esté codificando para el hardware, puede usar una capa de abstracción (a menudo proporcionada por el fabricante) o escribir la suya propia (según la hoja de datos y / o el código de ejemplo). Las abstracciones de C existentes de IME (mbed, cmsis, ...) a menudo son funcionales (casi) correctas, pero fallan horriblemente en el rendimiento (verifique los viejos arreglos y desplace alrededor de 6 capas de direccionamiento indirecto para una operación de conjunto de pin), usabilidad y portabilidad. Quieren exponerle a usted la funcionalidad todo del chip en particular, que en casi todos los casos no necesitará y no le importará, y bloquea su código a ese proveedor en particular (y probablemente a ese proveedor en particular). chip).
Esto es donde C ++ puede hacerlo mucho mejor: cuando se hace correctamente, un conjunto de pines puede pasar por 6 o más capas de abstracción (porque eso hace posible una mejor interfaz (¡portátil!) y un código más corto), pero proporciona una la interfaz que es independiente del destino para los casos simples , y sigue generando el mismo código de máquina que escribiría en el ensamblador .
Un fragmento del estilo de codificación que utilizo, que puede entusiasmarte o apartarte del horror:
// GPIO part of a HAL for atsam3xa
enum class _port { a = 0x400E0E00U, . . . };
template< _port P, uint32_t pin >
struct _pin_in_out_base : _pin_in_out_root {
static void direction_set_direct( pin_direction d ){
( ( d == pin_direction::input )
? ((Pio*)P)->PIO_ODR : ((Pio*)P)->PIO_OER ) = ( 0x1U << pin );
}
static void set_direct( bool v ){
( v ? ((Pio*)P)->PIO_SODR : ((Pio*)P)->PIO_CODR ) = ( 0x1U << pin );
}
};
// a general GPIO needs some boilerplate functionality
template< _port P, uint32_t pin >
using _pin_in_out = _box_creator< _pin_in_out_base< P, pin > >;
// an Arduino Due has an on-board led, and (suppose) it is active low
using _led = _pin_in_out< _port::b, 27 >;
using led = invert< pin_out< _led > >;
En realidad hay algunas capas más de abstracción. Sin embargo, el uso final del led, digamos que para encenderlo, no muestra la complejidad ni los detalles del objetivo (para un arduin uno o una pastilla azul ST32, el código sería idéntico).
target::led::init();
target::led::set( 1 );
El compilador no se siente intimidado por todas esas capas, y como no hay funciones virtuales involucradas, el optimizador ve todo (algunos detalles, omitidos, como habilitar el reloj periférico):
mov.w r2, #134217728 ; 0x8000000
ldr r3, [pc, #24]
str r2, [r3, #16]
str r2, [r3, #48]
Así es como lo habría escrito en el ensamblador - SI me hubiera dado cuenta de que los registros PIO se pueden usar con desplazamientos de una base común. En este caso, probablemente lo haría, pero el compilador es mucho mejor optimizando esas cosas que yo.
Por lo que tengo una respuesta, es: escriba una capa de abstracción para su hardware, pero hágalo en C ++ moderno (conceptos, plantillas) para que no dañe su rendimiento. Con eso en su lugar, puedes cambiar fácilmente a otro chip. Incluso puedes comenzar a desarrollar en un chip aleatorio que tengas, con el que estés familiarizado, con buenas herramientas de depuración, etc. y posponer la elección final hasta más tarde (cuando tengas más información sobre la memoria requerida, la velocidad de la CPU, etc.).
En mi opinión, una de las falacias del desarrollo integrado es elegir el chip primero (es una pregunta que se hace a menudo en este foro: en qué chip debería elegir ... La mejor respuesta es generalmente: no importa).
(edición: respuesta a "¿En cuanto al rendimiento, C o C ++ estarían al mismo nivel?")
Para las mismas construcciones, C y C ++ son iguales. C ++ tiene muchas más construcciones para la abstracción (solo algunas: clases, plantillas, constexpr) que, como cualquier herramienta, pueden usarse para lo bueno o para lo malo. Para que las discusiones sean más interesantes: no todos están de acuerdo en lo que es bueno o malo ...