Por que as pessoas usam uma variável para especificar um número de pino quando é improvável que o pino mude durante a execução do código?
Muitas vezes, vejo um int
ser usado para uma definição de pino,
int led = 13;
quando o uso de um const int
const int led = 13;
#define LED 13
faz muito mais sentido.
É mesmo em tutoriais no site do Arduino, por exemplo, o primeiro tutorial que a maioria das pessoas executa, o Blink .
Eu li em algum lugar que const int
é preferido #define
. Por que isso não é incentivado desde o início, em vez de permitir que as pessoas desenvolvam maus hábitos, desde o início? Eu notei isso há um tempo, mas recentemente isso começou a me irritar, daí a questão.
Memória / processamento / computação sábio é um const int
, enum
ou para que o assunto #define
, melhor do que uma planície int
, ou seja, ocupa menos memória, armazenados em memória diferente (Flash, EEPROM, SRAM), uma execução mais rápida, mais rápida para compilar?
Pode parecer uma duplicata de É melhor usar #define ou const int para constantes? , mas estou abordando a questão de por que as pessoas usam variáveis e como o desempenho melhora quando não usam, em vez de que tipo de constante é melhor.
fonte
Respostas:
Esse é o método correto. Ou até:
Quantos pinos você tem?
Alguns dos tutoriais não passaram pelo controle de qualidade que poderiam ter.
O desempenho será melhor usando
const byte
, compare comint
o compilador, no entanto, pode ser inteligente o suficiente para perceber o que você está fazendo.O que você pode fazer é incentivar gentilmente as pessoas a usar técnicas mais eficientes, usando-as em seu próprio código.
Respostas aos comentários
Um comentarista sugeriu que
byte
não é o padrão C. Isso está correto, no entanto, este é um site do Arduino StackExchange, e acredito que o uso de tipos padrão fornecidos pelo IDE do Arduino seja aceitável.No Arduino.h existe esta linha:
Observe que isso não é exatamente o mesmo que
unsigned char
. Consulte uint8_t vs char não assinado e Quando uint8_t char char não assinado? .Outro comentarista sugeriu que o uso de byte não melhorará necessariamente o desempenho, porque números menores do que
int
serão promovidos paraint
(consulte Regras de Promoção Inteira, se você quiser saber mais sobre isso).No entanto, no contexto de um identificador const , o compilador irá gerar código eficiente em qualquer caso. Por exemplo, desmontar "piscar" fornece isso na forma original:
De fato, gera o mesmo código se
13
:#define
const int
const byte
O compilador sabe quando pode caber um número em um registro e quando não pode. No entanto, é uma boa prática usar codificação que indique sua intenção . Tornar
const
claro que o número não será alterado e deixar clarobyte
(ouuint8_t
) deixa claro que você espera um número pequeno.Mensagens de erro confusas
Outro motivo importante para evitar
#define
são as mensagens de erro que você recebe se cometer um erro. Considere este esboço "intermitente" que possui um erro:Na superfície, parece bom, mas gera as seguintes mensagens de erro:
Você olha para a primeira linha destacada (linha 4) e nem vê o símbolo "=". Além disso, a linha parece bem. Agora é bastante óbvio qual é o problema aqui (
= 13
está sendo substituídoLED
), mas quando a linha está 400 linhas mais abaixo no código, não é óbvio que o problema está na maneira como o LED é definido.Já vi pessoas se apaixonarem por isso muitas vezes (inclusive eu).
fonte
int
é um exagero ... isto é, até o Arduino finalmente lançar a placa Tera ... :-)byte
tipo . Você quer dizerunsigned char
.byte
vez deint
, uma vez que , na maioria dos contextos, o valor inteiro com tipos menores do queint
os promovidosint
.C doesn't have a byte type. You mean unsigned char.
- Minha resposta foi no contexto do Arduino, que tem issotypedef uint8_t byte;
. Portanto, para um Arduino, usarbyte
está OK.Performance won't necessarily be better with byte instead of int
- ver post alterado.Como Ignacio afirma com razão, é basicamente porque eles não sabem melhor. E eles não sabem melhor porque as pessoas que os ensinaram (ou os recursos que eles usaram ao aprender) não sabiam melhor.
Grande parte do código e dos tutoriais do Arduino são escritos por pessoas que nunca tiveram nenhum treinamento em programação e são muito "autodidatas" a partir de recursos por pessoas que são elas mesmas autodidatas, sem treinamento adequado em programação.
Muitos dos trechos de código do tutorial que eu vejo em todo o lugar (e especialmente aqueles que estão disponíveis apenas nos vídeos do YouTube - urgh) seriam uma falha se eu os estivesse marcando em um exame.
Sim, a
const
é preferível a um não-const e até mesmo a#define
, porque:const
(como um#define
, diferente de um não-const) não aloca nenhuma RAMconst
(como um não-const, mas diferente de a#define
) fornece ao valor um tipo explícitoO segundo ponto é de particular interesse. A menos que seja especificado de outra forma com conversão de tipo incorporada (
(long)3
) ou sufixo de tipo (3L
) ou a presença de ponto decimal (3.0
), a#define
de um número sempre será um número inteiro e toda a matemática realizada nesse valor será como se fosse uma inteiro. Na maioria das vezes, isso não é um problema, mas você pode encontrar cenários interessantes ao tentar#define
armazenar um valor maior que um número inteiro, como por exemplo#define COUNT 70000
executar uma operação matemática com outrosint
valores. Ao usar a,const
você pode dizer ao compilador "Este valor deve ser tratado como esse tipo de variável" - então você usaria:const long count = 70000;
e tudo funcionaria conforme o esperado.Ele também tem o efeito indireto de verificar o tipo ao passar o valor ao redor do local. Tente passar a
const long
para uma função que espera umaint
e ela se queixaria de restringir o intervalo de variáveis (ou até mesmo falhar completamente na compilação, dependendo do cenário). Faça isso com um#define
e ele continuaria silenciosamente dando a você os resultados errados e o deixaria coçando a cabeça por horas.fonte
const
variável pode exigir RAM, dependendo do contexto, por exemplo, se for inicializada usando o valor de retorno de uma função não constexpr.const int foo = 13; bar(&foo);
definitivamente exigirá que o compilador aloque memória real parafoo
.int
compilador, o valor será o menor do tipo em que ele se ajustará (regras de módulo sobre assinado versus não assinado). Se você estiver em um sistema comint
16 bits,#define count 70000
parecerácount
umlong
, como se tivesse sido definido comoconst long count = 70000;
. Além disso, se você passar uma dessas versõescount
para uma função esperadaint
, qualquer compilador são tratá-las da mesma forma.#define COUNT 70000
não trunca em um int, mas o compilador a trata como um tipo grande o suficiente para armazenar esse número. É verdade que pode não ser óbvio quando você usaCOUNT
que não é um int, mas você pode dizer o mesmo sobre um deconst long
qualquer maneira.COUNT
no seu exemplo é substituído antes da compilação com a expressão70000
, que tem um tipo definido pelas regras de literais, como2
ou13L
ou4.0
são definidas pelas regras de literais. O fato de você usar#define
como alias essas expressões é irrelevante. Você pode usar#define
como alias pedaços arbitrários de código C, se desejar.Como um novato de duas semanas no Arduino, eu continuava com a ideia geral de o Arduino ser ocupado por não programadores. A maioria dos esboços que examinei, incluindo os do site do Arduino, mostra uma total falta de ordem, com esboços que não funcionam e quase nenhum comentário coerente à vista. Os fluxogramas são inexistentes e as "Bibliotecas" são uma confusão não moderada.
fonte
Minha resposta é ... eles fazem isso porque funciona. Estou tendo dificuldades para não fazer uma pergunta na minha resposta, como "por que tem que estar 'errado'?"
fonte