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 #define
s para constantes. Hay un número de razones para esto:
- No puede establecer tamaños de matriz usando
const int
. - No puede usar
const int
como etiquetas de declaración de caso (aunque esto funciona en algunos compiladores) - No se puede inicializar a
const
con 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 const
y algunos usando una mezcla.
programming
c++
coding-standards
Cybergibbons
fuente
fuente
#define
es 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,const
por lo que la única opción es usar#define
ay dejar que el compilador lo sustituya como entrada de texto antes de interpretar el significado.Respuestas:
Es importante tener en cuenta que
const int
no 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 int
constantes son valores de tiempo de compilación y se pueden usar para establecer límites de matriz, como etiquetas de caso, etc.const int
las 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
#define
para 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 usarenum
y 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á unaconst
variable. 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
const
variables 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
const
variable 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
const
variable vs. a#define
puede afectar el lugar donde se almacenan los datos en la memoria, lo que puede obligarlo a usar uno u otro.const
las variables (generalmente) se almacenarán en SRAM, junto con todas las demás variables.#define
menudo 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
PROGMEM
palabra 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
#define
Es para definir números de pin analógicos, ya que son alfanuméricos.
Claro, puede codificar los números de PIN como
a2
,a3
etc., 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
const
pin sería apropiado para un pin definido comoA5
.En esos casos siempre uso
#define
Divisor de voltaje Ejemplo:
Todas las variables de configuración están en la parte superior y nunca habrá un cambio en el valor,
adcPin
excepto en el momento de la compilación.No te preocupes por qué tipo
adcPin
es. Y no se usa RAM adicional en el binario para almacenar una constante.El compilador simplemente reemplaza cada instancia de
adcPin
con la cadenaA5
antes 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
true
yfalse
como booleano para ahorrar RAMMucho de esto se reduce a preferencias personales, sin embargo, está claro que
#define
es más versátil.fuente
const
no usará más RAM que a#define
. Y para los pines analógicos, los definiría comoconst uint8_t
, aunqueconst int
no haría ninguna diferencia.const
realidad no usa más RAM [...] hasta que realmente se usa ". Te perdiste mi punto: la mayoría de las veces, aconst
no 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 .