Arduino es un híbrido extraño, donde se utiliza alguna funcionalidad de C ++ en el mundo integrado, tradicionalmente un entorno C. De hecho, una gran cantidad de código Arduino es muy similar a C.
C ha usado tradicionalmente #defines para constantes. Hay un número de razones para esto:
- No puede establecer tamaños de matriz usando
const int. - No puede usar
const intcomo etiquetas de declaración de caso (aunque esto funciona en algunos compiladores) - No se puede inicializar a
constcon otroconst.
Puede consultar esta pregunta en StackOverflow para obtener más razonamiento.
Entonces, ¿qué debemos usar para Arduino? Tiendo hacia #define, pero veo algo de código usando consty algunos usando una mezcla.
programming
c++
coding-standards
Cybergibbons
fuente
fuente

#definees la opción obvia. Mi ejemplo es nombrar pines analógicos, como A5. No hay un tipo apropiado para él que pueda usarse como un,constpor lo que la única opción es usar#defineay dejar que el compilador lo sustituya como entrada de texto antes de interpretar el significado.Respuestas:
Es importante tener en cuenta que
const intno se comporta de manera idéntica en C y en C ++, por lo que, de hecho, varias de las objeciones en su contra a las que se ha aludido en la pregunta original y en la amplia respuesta de Peter Bloomfields no son válidas:const intconstantes son valores de tiempo de compilación y se pueden usar para establecer límites de matriz, como etiquetas de caso, etc.const intlas constantes no necesariamente ocupan ningún almacenamiento. A menos que tome su dirección o la declare externa, generalmente tendrán una existencia en tiempo de compilación.Sin embargo, para las constantes de enteros, a menudo puede ser preferible usar un (con nombre o anónimo)
enum. A menudo me gusta esto porque:const int(cada bit como seguro en C ++ 11).Entonces, en un programa idiomático de C ++, no hay ninguna razón para usar
#definepara definir una constante entera. Incluso si desea seguir siendo compatible con C (debido a requisitos técnicos, porque está abandonando la vieja escuela o porque las personas con las que trabaja lo prefieren de esa manera), aún puede usarenumy debe hacerlo, en lugar de usar#define.fuente
const int. Para los tipos más complejos, tiene razón en que se puede asignar almacenamiento, pero aun así, es poco probable que esté peor que con un#define.EDITAR: microtherion da una excelente respuesta que corrige algunos de mis puntos aquí, particularmente sobre el uso de memoria.
Como ha identificado, hay ciertas situaciones en las que se ve obligado a usar a
#define, porque el compilador no permitirá unaconstvariable. Del mismo modo, en algunas situaciones se ve obligado a usar variables, como cuando necesita una matriz de valores (es decir, no puede tener una matriz de#define).Sin embargo, hay muchas otras situaciones en las que no hay necesariamente una sola respuesta "correcta". Aquí hay algunas pautas que seguiría:
Tipo de seguridad
Desde un punto de vista de programación general, las
constvariables son generalmente preferibles (cuando sea posible). La razón principal de esto es la seguridad de tipo.Una
#define(macro de preprocesador) copia directamente el valor literal en cada ubicación del código, haciendo que cada uso sea independiente. Hipotéticamente, esto puede dar lugar a ambigüedades, porque el tipo puede terminar resolviéndose de manera diferente dependiendo de cómo / dónde se use.Una
constvariable es solo un tipo, que se determina por su declaración y se resuelve durante la inicialización. A menudo requerirá una conversión explícita antes de que se comporte de manera diferente (aunque hay varias situaciones en las que puede promocionarse de forma implícita de forma segura). Como mínimo, el compilador puede (si está configurado correctamente) emitir una advertencia más confiable cuando ocurre un problema de tipo.Una posible solución para esto es incluir una conversión explícita o un sufijo de tipo dentro de a
#define. Por ejemplo:Sin embargo, ese enfoque puede causar problemas de sintaxis en algunos casos, dependiendo de cómo se use.
Uso de la memoria
A diferencia de la informática de propósito general, la memoria es obviamente una prima cuando se trata de algo así como un Arduino. El uso de una
constvariable vs. a#definepuede afectar el lugar donde se almacenan los datos en la memoria, lo que puede obligarlo a usar uno u otro.constlas variables (generalmente) se almacenarán en SRAM, junto con todas las demás variables.#definemenudo se almacenarán en el espacio del programa (memoria Flash), junto con el propio boceto.(Tenga en cuenta que hay varias cosas que pueden afectar exactamente cómo y dónde se almacena algo, como la configuración y optimización del compilador).
SRAM y Flash tienen limitaciones diferentes (por ejemplo, 2 KB y 32 KB respectivamente para el Uno). Para algunas aplicaciones, es bastante fácil quedarse sin SRAM, por lo que puede ser útil cambiar algunas cosas a Flash. Lo contrario también es posible, aunque probablemente sea menos común.
PROGMEM
Es posible obtener los beneficios de la seguridad de escritura mientras se almacenan los datos en el espacio del programa (Flash). Esto se hace usando la
PROGMEMpalabra clave. No funciona para todos los tipos, pero se usa comúnmente para matrices de enteros o cadenas.La forma general que figura en la documentación es la siguiente:
Las tablas de cadenas son un poco más complicadas, pero la documentación tiene todos los detalles.
fuente
Para las variables de un tipo especificado que no se alteran durante la ejecución, generalmente se puede usar cualquiera.
Para los números de pin digitales contenidos en las variables, cualquiera puede funcionar, como:
Pero hay una circunstancia donde siempre uso
#defineEs para definir números de pin analógicos, ya que son alfanuméricos.
Claro, puede codificar los números de PIN como
a2,a3etc., en todo el programa y el compilador sabrá qué hacer con ellos. Luego, si cambia los pines, entonces cada uso necesitaría ser cambiado.Además, siempre me gusta tener mis definiciones de pin en la parte superior, todo en un solo lugar, por lo que la pregunta se convierte en qué tipo de
constpin sería apropiado para un pin definido comoA5.En esos casos siempre uso
#defineDivisor de voltaje Ejemplo:
Todas las variables de configuración están en la parte superior y nunca habrá un cambio en el valor,
adcPinexcepto en el momento de la compilación.No te preocupes por qué tipo
adcPines. Y no se usa RAM adicional en el binario para almacenar una constante.El compilador simplemente reemplaza cada instancia de
adcPincon la cadenaA5antes de compilar.Hay un interesante hilo del Foro Arduino que analiza otras formas de decidir:
#define vs.const variable (foro Arduino)
Excertps:
Sustitución de código:
Código de depuración:
Definiendo
trueyfalsecomo booleano para ahorrar RAMMucho de esto se reduce a preferencias personales, sin embargo, está claro que
#definees más versátil.fuente
constno usará más RAM que a#define. Y para los pines analógicos, los definiría comoconst uint8_t, aunqueconst intno haría ninguna diferencia.constrealidad no usa más RAM [...] hasta que realmente se usa ". Te perdiste mi punto: la mayoría de las veces, aconstno usa RAM, incluso cuando se usa . Entonces, " este es un compilador multipass ". Lo más importante, es un compilador optimizador . Siempre que sea posible, las constantes se optimizan en operandos inmediatos .