Quando e para que propósitos a palavra-chave const deve ser usada em C para variáveis?

48

Ao obter meu código revisou aqui o problema de usar o const palavra-chave surgiu. Eu entendo que ele é usado para implementar o comportamento somente leitura em variáveis.

Estou confuso sobre quais são as várias situações em que isso pode ser útil.

  • Deve ser usado para fins de clareza em protótipos de funções?
  • Deve ser usado como uma medida de segurança durante o desenvolvimento do código?
  • Deve ser usado no escopo de várias funções para declarar constantes de tempo de execução?
  • Deverá ser usado?

Essa pergunta é apenas um exemplo da confusão que estou enfrentando. A confusão geral é

  • Quando deve ser a palavra-chave const usada na programação C?
  • Quais são os vários tipos de benefícios que podem ser obtidos usando essa palavra-chave em C?
  • Existe algum contras de usar const palavra-chave?

Tem sido apontado que esta questão pode ser muito ampla devido a todas essas questões no detalhe da minha pergunta. Eu só queria esclarecer que essas perguntas são apenas para esclarecer a confusão sobre a questão principal.

When and for what purposes should the const keyword be used in C for variables?

Também pode ser reformulado como

The proper use of const keyword in C' with the pros and cons of the same.

    
por Aseem Bansal 11.07.2013 / 16:04
fonte

4 respostas

55

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.

    
por 13.07.2013 / 16:05
fonte
7

Geralmente, em qualquer linguagem de programação, recomenda-se usar const ou o modificador equivalente, já que

  • Pode esclarecer ao chamador que o que eles passaram não vai mudar
  • Melhorias potenciais de velocidade, uma vez que o compilador sabe ao certo que pode omitir certas coisas que são relevantes apenas se o parâmetro puder mudar
  • Proteção contra alteração acidental do valor
por 11.07.2013 / 17:05
fonte
1

Sim, é basicamente a resposta do TheLQ.

É uma medida de segurança para o programador, para que você não modifique uma variável e não chame funções que possam modificá-las. Em uma matriz ou estrutura, o especificador const indica que os valores de seu conteúdo não serão modificados e até mesmo o compilador não permitirá que você faça isso. Você ainda pode facilmente alterar o valor da variável com apenas uma conversão.

No que eu geralmente vejo, é usado principalmente para adicionar valores constantes no código e para indicar que a matriz ou estrutura não será modificada se você chamar uma função específica. Esta última parte é importante, porque quando você chama uma função que irá modificar sua matriz ou estrutura, você pode querer manter a versão original, então você cria uma cópia da variável e a passa para a função. Se não for esse o caso, você não precisa da cópia, obviamente, por exemplo, você pode mudar,

int foo(Structure s);

para

int foo(const Structure * s);

e não recebendo a sobrecarga da cópia.

Apenas para adicionar, observe que C possui regras específicas com o especificador const. Por exemplo,

int b = 1;
const int * a = &b;

não é o mesmo que

int b = 1;
int * const a = &b;

O primeiro código não permitirá que você modifique um arquivo. No segundo caso, o ponteiro é constante, mas seu conteúdo não é, então o compilador permitirá que você diga * a = 3; sem um erro do compilador, mas você não pode fazer com que a seja uma referência a outra coisa.

    
por 13.07.2013 / 15:09
fonte
0

De acordo com as declarações do TheLQ:

Ao trabalhar com uma equipe de programadores declarando const é uma boa maneira de indicar que a dita variável não deve ser modificada, ou apenas para se lembrar de grandes projetos. É útil nesse sentido e pode salvar muitas dores de cabeça.

    
por 13.07.2013 / 14:19
fonte