Ao revisar o código, aplico as seguintes regras:
Sempre use const
para parâmetros de função passados por referência onde a 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, de outra forma, poderiam ser definidas usando um #define ou um enum. O compilador pode localizar os dados na memória somente leitura (ROM) como resultado (embora o vinculador seja frequentemente uma ferramenta melhor para essa finalidade em sistemas incorporados).
const double PI = 3.14;
Nunca use const em um protótipo de função 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);
Onde apropriado, use const volatile
em locais que não podem ser alterados pelo programa, mas que ainda podem mudar. Os registros 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 na implementação da função 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 função retornam valores 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 const
apenas indicam que você não alterará a variável; eles não mudam como ou onde a variável é armazenada. Obviamente, o compilador pode descobrir que uma variável não é alterada, mas adicionando const
você permite que isso seja imposto. Isso pode ajudar o leitor e adicionar um pouco de segurança (embora, se suas funções forem grandes ou complicadas o suficiente para que isso faça uma grande diferença, você possa ter outros problemas). Editar - por exemplo. uma função densamente codificada de 200 linhas com loops aninhados e muitos nomes de variáveis longos ou semelhantes, sabendo que determinadas variáveis nunca mudam podem facilitar a compreensão significativa. Tais funções foram mal projetadas ou mantidas.
Problemas com const
. Você provavelmente ouvirá o termo "envenenamento const". Isso ocorre quando adicionar const
um parâmetro de função faz com que 'constness' se propague.
Edit - envenenamento const: por exemplo, na função:
int function_a(char * str, int n)
{
...
function_b(str);
...
}
se mudarmos str
para const
, devemos garantir que isso fuction_b
também leva a const
. E assim por diante, se function_b
passa str
para function_c
etc. Como você pode imaginar, isso pode ser doloroso se propagar em muitos arquivos / módulos separados. Se ele se propagar para uma função que não pode ser alterada (por exemplo, uma biblioteca do sistema), uma conversão se torna necessária. Portanto, espalhar o
const
código existente talvez esteja causando problemas. No entanto, no novo código, é melhor const
qualificar - se consistentemente, quando apropriado.
O problema mais insidioso const
é que ele não estava no idioma original. Como complemento, ele não se encaixa perfeitamente. Para começar, ele tem dois significados (como nas regras acima, significando "Não vou mudar isso" e "isso não pode ser modificado"). Mas mais do que isso, pode ser perigoso. Por exemplo, compile e execute esse código e (dependendo do compilador / opções) poderá travar ao executar:
const char str[] = "hello world\n";
char *s = strchr(str, '\n');
*s = '\0';
strchr
retorna um char*
não a const char*
. Como seu parâmetro de chamada,
const
ele deve converter o parâmetro de chamada para char*
. E, nesse caso, isso elimina a propriedade de armazenamento real somente leitura. Editar: - isso se aplica geralmente a vars na memória somente leitura. Por 'ROM', quero dizer não apenas a ROM física, mas qualquer memória protegida contra gravação, como acontece com a seção de código dos programas executados em um sistema operacional típico.
Muitas funções padrão da biblioteca se comportam da mesma maneira, portanto, tenha cuidado: quando você tem constantes reais (ou seja, armazenadas na ROM), você deve ter muito cuidado para não perder a consistência.
Specific issues with software development
. Eu estou sendo bem específico.