¿Por qué las personas usan una variable para especificar un número de pin cuando es poco probable que el pin cambie durante la ejecución del código?
Muchas veces veo un int
ser utilizado para una definición de pin,
int led = 13;
cuando el uso de un const int
const int led = 13;
#define LED 13
Tiene mucho más sentido.
Incluso está en los tutoriales en el sitio de Arduino, por ejemplo, el primer tutorial que ejecuta la mayoría de la gente, Blink .
Me leído en alguna parte que const int
se prefiere sobre #define
. ¿Por qué no se fomenta esto desde el principio, en lugar de permitir que las personas desarrollen malos hábitos desde el principio? Lo noté hace un tiempo, pero recientemente ha comenzado a irritarme, de ahí la pregunta.
Memoria / procesamiento / computación inteligente es una const int
, enum
o para el caso #define
, mejor que una llanura int
, es decir, ocupa menos memoria, almacenado en memoria diferentes (Flash, EEPROM, SRAM), más rápida ejecución, más rápido para compilar?
Esto puede parecer un duplicado de ¿Es mejor usar #define o const int para constantes? , pero estoy abordando la pregunta de por qué las personas usan variables y cómo mejora el rendimiento cuando no lo hacen, en lugar de qué tipo de constante es mejor.
fuente
Respuestas:
Ese es el método correcto. O incluso:
¿Cuántos pines tienes?
Algunos de los tutoriales no pasaron por tanto control de calidad como podrían haberlo hecho.
El rendimiento será mejor usando
const byte
, en comparación,int
sin embargo, el compilador puede ser lo suficientemente inteligente como para darse cuenta de lo que está haciendo.Lo que puede hacer es alentar suavemente a las personas a usar técnicas más eficientes al usarlas en su propio código.
Respuestas a comentarios
Un comentarista ha sugerido que
byte
no es el estándar C. Esto es correcto, sin embargo, este es un sitio de Arduino StackExchange, y creo que es aceptable usar los tipos estándar proporcionados por el IDE de Arduino.En Arduino.h hay esta línea:
Tenga en cuenta que esto no es exactamente lo mismo que
unsigned char
. Ver uint8_t vs unsigned char y ¿ Cuándo es uint8_t ≠ unsigned char? .Otro comentarista ha sugerido que el uso de byte no necesariamente mejorará el rendimiento, porque los números menores a los que
int
se promocionaránint
(consulte Reglas de promoción de enteros si desea obtener más información al respecto).Sin embargo, en el contexto de un identificador constante , el compilador generará un código eficiente en cualquier caso. Por ejemplo, desarmar "parpadeo" le da esto en la forma original:
De hecho, genera el mismo código si
13
:#define
const int
const byte
El compilador sabe cuándo puede caber un número en un registro y cuándo no. Sin embargo, es una buena práctica usar una codificación que indique su intención . Dejarlo en
const
claro deja claro que el número no cambiará, y dejarlo clarobyte
(ouint8_t
) deja claro que espera un número pequeño.Mensajes de error confusos
Otra razón importante para evitar
#define
es los mensajes de error que recibe si comete un error. Considere este bosquejo de "parpadeo" que tiene un error:En la superficie se ve bien, pero genera estos mensajes de error:
Miras la primera línea resaltada (línea 4) y ni siquiera ves un símbolo "=". Además, la línea se ve bien. Ahora es bastante obvio cuál es el problema aquí (
= 13
se está sustituyendoLED
), pero cuando la línea está 400 líneas más abajo en el código, no es obvio que el problema esté en la forma en que se define el LED.He visto a personas caer en esto muchas veces (incluido yo mismo).
fuente
int
es excesivo ... es decir, hasta que Arduino finalmente salga con el tablero Tera ... :-)byte
tipo . ¿Quiere decirunsigned char
.byte
lugar deint
, ya que, en la mayoría de los contextos, el valor entero con tipos más pequeños de los queint
se promuevenint
.C doesn't have a byte type. You mean unsigned char.
- Mi respuesta fue en el contexto Arduino, que tiene estotypedef uint8_t byte;
. Entonces, para un Arduino, usarbyte
está bien.Performance won't necessarily be better with byte instead of int
- Ver publicación modificada.Como Ignacio dice correctamente, es básicamente porque no saben mejor. Y no saben mejor porque las personas que les enseñaron (o los recursos que usaron cuando aprendieron) no sabían mejor.
Gran parte del código y los tutoriales de Arduino están escritos por personas que nunca han recibido capacitación en programación y son muy "autodidactas" de los recursos de personas que son muy autodidactas sin la capacitación adecuada en programación.
Muchos de los fragmentos de código tutorial que veo alrededor del lugar (y especialmente aquellos que solo están disponibles en los videos de YouTube --- urgh) serían una marca de falla si los marcara en un examen.
Sí,
const
se prefiere a sobre una no constante, e incluso sobre una#define
, porque:const
(como a#define
, a diferencia de un no constante) no asigna ninguna RAMconst
(como un no constante, pero a diferencia de a#define
) le da al valor un tipo explícitoEl segundo punto allí es de particular interés. A menos que se indique específicamente lo contrario con la conversión de tipos incrustada (
(long)3
) o un sufijo de tipo (3L
) o la presencia de un punto decimal (3.0
),#define
un número siempre será un número entero y todas las matemáticas realizadas en ese valor serán como si fuera un entero. La mayoría de las veces eso no es un problema, pero puede encontrarse con escenarios interesantes cuando intenta#define
un valor que es más grande de lo que un entero puede almacenar, como#define COUNT 70000
y luego realizar una operación matemática con otrosint
valores. Al usar unconst
, puede decirle al compilador "Este valor debe tratarse como este tipo de variable", por lo que en su lugar usaría:const long count = 70000;
y todo funcionaría como se esperaba.También tiene el efecto knock-on que comprueba el tipo al pasar el valor alrededor del lugar. Intente pasar un
const long
a una función que espera unint
y se quejaría de reducir el rango de variables (o incluso no compilará por completo según el escenario). Haga eso con un#define
y simplemente continuaría silenciosamente dándole los resultados incorrectos y lo dejaría rascándose la cabeza durante horas.fuente
const
variable puede requerir RAM, dependiendo del contexto, por ejemplo, si se inicializa utilizando el valor de retorno de una función no constexpr.const int foo = 13; bar(&foo);
definitivamente requerirá que el compilador asigne memoria real parafoo
.int
compilador, el compilador considera que el valor tiene el tipo más pequeño en el que se ajustará (reglas de módulo sobre con signo y sin signo). Si está en un sistema deint
16 bits,#define count 70000
tendrá elcount
aspecto de unlong
, como si se hubiera definido comoconst long count = 70000;
. Además, si pasa cualquiera de esas versionescount
a una función que esperaint
, cualquier compilador sensato las tratará de la misma manera.#define COUNT 70000
no se trunca en un int, pero el compilador lo trata como un tipo lo suficientemente grande como para contener ese número. Es cierto que puede no ser obvio cuando usaCOUNT
que no es un int, pero podría decir lo mismo sobre un deconst long
todos modos.COUNT
en su ejemplo se reemplaza antes de la compilación con la expresión70000
, que tiene un tipo definido por las reglas de literales, al igual que2
o13L
o4.0
son definidos por las normas de literales. El hecho de que utilice#define
para alias esas expresiones es irrelevante. Puede usar#define
alias de fragmentos arbitrarios de código C, si lo desea.Como novato de 2 semanas en Arduino, retomaría la idea general de que Arduino está ocupado por no programadores. La mayoría de los bocetos que he examinado, incluidos los del sitio de Arduino, muestran una falta total de orden, con bocetos que no funcionan y apenas un comentario coherente a la vista. Los diagramas de flujo no existen, y las "Bibliotecas" son un revoltijo no moderado.
fuente
Mi respuesta es ... lo hacen porque funciona. Me cuesta mucho no hacer una pregunta en mi respuesta como "¿por qué tiene que estar 'equivocado'?"
fuente