EDIT: microtherion fornece uma excelente resposta que corrige alguns dos meus pontos aqui, particularmente sobre o uso de memória.
Como você identificou, há certas situações em que você é forçado a usar a #define
, porque o compilador não permite uma const
variável. Da mesma forma, em algumas situações, você é forçado a usar variáveis, como quando precisa de uma matriz de valores (ou seja, não pode ter uma matriz de #define
).
No entanto, existem muitas outras situações em que não há necessariamente uma única resposta 'correta'. Aqui estão algumas diretrizes que eu seguiria:
Segurança do tipo
Do ponto de vista geral da programação, as const
variáveis são geralmente preferíveis (sempre que possível). A principal razão para isso é a segurança do tipo.
Uma #define
(macro de pré-processador) copia diretamente o valor literal em cada local no código, tornando cada uso independente. Hipoteticamente, isso pode resultar em ambiguidades, porque o tipo pode acabar sendo resolvido de maneira diferente, dependendo de como / onde é usado.
Uma const
variável é apenas um tipo, que é determinado por sua declaração e resolvido durante a inicialização. Geralmente, exige uma conversão explícita antes de se comportar de maneira diferente (embora existam várias situações nas quais ele pode ser implicitamente promovido com segurança). No mínimo, o compilador pode (se configurado corretamente) emitir um aviso mais confiável quando ocorrer um problema de tipo.
Uma solução possível para isso é incluir uma conversão explícita ou um sufixo de tipo em a #define
. Por exemplo:
#define THE_ANSWER (int8_t)42
#define NOT_QUITE_PI 3.14f
Essa abordagem pode potencialmente causar problemas de sintaxe em alguns casos, dependendo de como é usada.
Uso da memória
Ao contrário da computação de uso geral, a memória é obviamente superior quando se lida com algo como um Arduino. O uso de uma const
variável vs. a #define
pode afetar o local em que os dados são armazenados na memória, o que pode forçá-lo a usar um ou outro.
const
variáveis (geralmente) serão armazenadas na SRAM, juntamente com todas as outras variáveis.
- Os valores literais usados
#define
geralmente serão armazenados no espaço do programa (memória Flash), ao lado do próprio esboço.
(Observe que existem várias coisas que podem afetar exatamente como e onde algo é armazenado, como configuração e otimização do compilador.)
SRAM e Flash têm limitações diferentes (por exemplo, 2 KB e 32 KB, respectivamente, para o Uno). Para alguns aplicativos, é muito fácil ficar sem SRAM, portanto, pode ser útil mudar algumas coisas para o Flash. O inverso também é possível, embora provavelmente menos comum.
PROGMEM
É possível obter os benefícios da segurança de tipo e também armazenar os dados no espaço do programa (Flash). Isso é feito usando a PROGMEM
palavra - chave Não funciona para todos os tipos, mas é comumente usado para matrizes de números inteiros ou seqüências de caracteres.
A forma geral fornecida na documentação é a seguinte:
dataType variableName[] PROGMEM = {dataInt0, dataInt1, dataInt3...};
As tabelas de strings são um pouco mais complicadas, mas a documentação possui detalhes completos.