Ao revisar o código, aplico as seguintes regras:
-
Sempre use
const
para os parâmetros de função passados por referência onde o função não modifica (ou libera) os dados apontados.int find(const int *data, size_t size, int value);
-
Sempre use
const
para constantes que poderiam ser definidas usando #define ou enum. O compilador pode localizar os dados na memória somente leitura (ROM) como resultado (embora o vinculador seja freqüentemente uma ferramenta melhor para essa finalidade em sistemas embarcados).const double PI = 3.14;
-
Nunca use const em uma função prototype para um parâmetro passado por valor . Não tem significado e é, portanto, apenas "ruído".
// don't add const to 'value' or 'size' int find(const int *data, size_t size, const int value);
-
Quando apropriado, use
const volatile
em locais que não podem ser alterados pelo programa, mas que ainda podem ser alterados. Registradores de hardware são o caso de uso típico aqui, por exemplo, um registro de status que reflete um estado do dispositivo:const volatile int32_t *DEVICE_STATUS = (int32_t*) 0x100;
Outros usos são opcionais. Por exemplo, os parâmetros para uma função dentro da função implementation podem ser marcados como const.
// 'value' and 'size can be marked as const here
int find(const int *data, const size_t size, const int value)
{
... etc
ou valores de retorno de função ou cálculos que são obtidos e nunca mudam:
char *repeat_str(const char *str, size_t n)
{
const size_t len = strlen(str);
const size_t buf_size = 1 + (len * n);
char *buf = malloc(buf_size);
...
Esses usos de const
apenas indicam que você não alterará a variável; eles não mudam como ou onde a variável é armazenada. O compilador pode, é claro, descobrir que uma variável não é alterada, mas adicionando const
, você permite que ela imponha isso. Isso pode ajudar o leitor e adicionar alguma segurança (embora se suas funções forem grandes ou
complicado o suficiente para que isso faça uma grande diferença, você pode ter outra
problemas). Editar - por exemplo. uma função de 200 linhas densamente codificada com loops aninhados e muitos longos
ou nomes de variáveis similares, sabendo que certas variáveis nunca mudam
facilidade understaning significativamente. Tais funções foram mal projetadas ou
mantido.
Problemas com const
. Você provavelmente ouvirá o termo "envenenamento por const".
Isso ocorre quando a adição de const
a um parâmetro de função faz com que 'constness' seja
propagar.
Edit - const envenenamento: por exemplo, na função:
int function_a(char * str, int n)
{
...
function_b(str);
...
}
se alterarmos str
para const
, devemos garantir que fuction_b
também
um código%. E assim por diante, se const
passar o function_b
para str
,
Como você pode imaginar, isso pode ser doloroso se se propagar para muitos
arquivos / módulos separados. Se ele se propaga para uma função que não pode ser
alterado (por exemplo, uma biblioteca do sistema), então um elenco se torna necessário. Então aspersão
function_c
no código existente talvez esteja causando problemas. Em novo código
no entanto, é melhor que const
se qualifique de forma consistente quando apropriado.
O problema mais insidioso de const
é que não estava no original
língua. Como um complemento, não se encaixa perfeitamente. Para começar, tem dois significados
(como nas regras acima, significando "Eu não vou mudar isso" e "isso não pode ser modificado"). Mas mais que isso, pode ser perigoso. Por exemplo, compile e
executar este código e (dependendo do compilador / opções) ele pode falhar quando
executar:
const char str[] = "hello world\n";
char *s = strchr(str, '\n');
*s = 'int find(const int *data, size_t size, int value);
';
const
retorna um strchr
não um char*
. Como seu parâmetro de chamada é
const char*
deve converter o parâmetro de chamada em const
. E neste caso
elimina a propriedade de armazenamento real somente leitura. Edit: - isso se aplica geralmente a vars na memória somente leitura. Por 'ROM', quero dizer não apenas ROM físico, mas qualquer memória que é protegida contra gravação, como acontece com a seção de código de programas executados em um sistema operacional típico.
Muitas funções da biblioteca padrão se comportam da mesma maneira, portanto, cuidado: quando você tem constantes reais (ou seja, armazenadas na ROM) você deve ser muito cuidadoso para não perder sua constância.