¿Cuáles son los fragmentos / trucos / hacks de código C incrustado absolutamente pequeños que debe conocer para un código de sistema incrustado?

Aquí como algunos de mis favoritos:

Campos de bits: aproveche al máximo su recurso más preciado, RAM, utilizando bits individuales dentro de una estructura para representar diferentes variables booleanas (verdadero / falso, encendido / apagado, etc.) utilizando el mecanismo de campo de bits C. Esto reducirá la cantidad de RAM que tomarán sus variables booleanas en un factor de aproximadamente 8.

Reutilización variable: este “truco” rompe las reglas de las mejores prácticas de desarrollo de software, pero si sabe lo que está haciendo, funciona muy bien. Encuentre 2 o más variables globales en su sistema del mismo tipo cuyo uso no se superponga entre sí (mientras se usa una, la otra no); esto es fundamental para que esta técnica funcione. Use una sola variable del tipo dado para reemplazar las otras, y luego use esta única variable en todos los lugares donde solía usar diferentes variables. No afirmo que esto no sea peligroso, pero puede funcionar sin errores si tienes mucho cuidado con lo que estás haciendo. Por supuesto, esto es bueno para sistemas con RAM muy limitada; si tiene suficiente RAM, entonces es mejor no hacerlo (para aquellos de ustedes que puedan pensar que este ‘truco’ es ridículo, estúpido o peligroso, recuerden que algunos incorporados los sistemas usan procesadores de 8 bits con tan solo 256 bytes de RAM: ¡cada byte cuenta! ¡Este no es el mundo del escritorio!)

Cálculos con valores estáticos: si hay algún cálculo en su código que se puede hacer por completo en tiempo de compilación, ¡entonces hágalo por todos los medios! Mire las entradas de todos sus cálculos y pregúntese “¿utiliza todo o parte de este cálculo cualquier valor estático que pueda conocerse en tiempo de compilación”. Evite cosas como asignar un valor “codificado” a una variable, luego use la variable en su cálculo; en su lugar, use un “#define” para el valor y luego use la etiqueta de definición en su código en lugar de la variable. Especialmente en los casos de multiplicación y división, esto puede ahorrarle preciosos ciclos de CPU.

Multiplica y divide por potencias de 2: esta técnica es bien conocida, pero la incluyo de todos modos para aquellos que pueden no saberlo. Siempre que necesite multiplicar o dividir un valor entero por un valor que sea una potencia de 2, utilice el desplazamiento de bits en lugar de una multiplicación o división real. Para multiplicar por 2, cambie su valor a la izquierda por uno (2 a la potencia de 1). Para multiplicar por 4, cambie su valor a la izquierda por 2 (2 a la potencia de 2), y así sucesivamente. Para dividir un valor por una potencia de 2 simplemente cambie a la derecha en lugar de a la izquierda. Los ciclos de CPU guardados son tremendos.

Utilice bucles “while (1)”: un bucle “while (1)” es simplemente una “fachada” sintáctica que realmente equivale a un simple “goto”, el tipo de mecanismo de bucle más eficiente disponible. Use una declaración de “interrupción” para salir del ciclo (que en realidad es solo un “ir a” a la instrucción que sigue a su ciclo). A mí mismo, me encantaría usar gotos directamente en mi código, pero hacerlo corre el riesgo de causar un ataque cardíaco a alguien durante las revisiones del código, mientras que a nadie parece importarle cuando uso una combinación while (1) / break en su lugar.

Use construcciones de interruptor / caso: Use construcciones de interruptor / caso cuando sea posible para reemplazar una serie de bloques “if” o “if / else”. La construcción de interruptor / caja en C es simplemente otra “fachada” para un goto. Por lo general, ahorrará ciclos de CPU al hacerlo.

Use solo la función “principal”: aquí rompo todas las reglas y me pongo mi traje de asbesto para las llamas que seguramente seguirán. Olvídate de crear otras funciones que no sean “main ()”. Escriba su código todo en main () de forma lineal. Usa gotos para realizar ramas. Tenga en cuenta que en este caso puede declarar sus variables como globales fuera de main () o como locales dentro de main (); no importa, ya que con este tipo de codificación ambos son esencialmente equivalentes, ya que su código nunca funcionará cualquier cosa con la pila. Y, si declara todas sus variables fuera de main (), entonces no necesita una pila en absoluto: establezca el tamaño de su pila en cero (la técnica para hacerlo varía de un conjunto de herramientas a otro) y reclame esa preciosa RAM para otros usos. El uso de esta técnica también evita toda la sobrecarga de la CPU relacionada con las llamadas a funciones. Por supuesto, estamos hablando de pequeños programas para pequeños sistemas integrados; en la mayoría de los demás casos, esta no es una buena técnica para usar. Si lleva este tipo de código a una revisión de código, ¡tenga a los paramédicos esperando, ya que seguramente les dará a algunos de sus colegas ingenieros de software un ataque cardíaco masivo! 😉

Muy a menudo en dispositivos integrados, como sus teléfonos inteligentes, hay una gran escasez de recursos como la energía y los ciclos de reloj de la CPU. Simplemente no puede terminar escribiendo código para dividir los valores de píxeles de una imagen utilizando el operador de división.

A menudo se prefiere un desplazamiento a la izquierda por uno, ya que es computacionalmente menos costoso. Potencialmente, eso podría significar una hora extra desperdiciada en Facebook o gastada escribiendo una respuesta bien investigada en Quora. Aquí hay una lista completa de trucos que explotan la manipulación de bits para evitar el uso de CPU siempre que sea posible.

Bit Twiddling Hacks

Un pensamiento,
vale la pena compartir.