Quando e com que finalidade a palavra-chave const deve ser usada em C para variáveis?

58

Ao revisar meu código aqui,const surgiu a questão do uso da palavra - chave. Entendo que é usado para implementar o comportamento somente leitura em variáveis.

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

  • Deve ser usado por uma questão de clareza nos protótipos de função?
  • 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 em tempo de execução?
  • Deve ser usado?

Essas perguntas são apenas exemplos da confusão que estou enfrentando. A confusão geral é

  • Quando deve ser a constpalavra - chave 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?
  • Existem contras no uso da constpalavra-chave?


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

Quando e com que finalidade a palavra-chave const deve ser usada em C para variáveis?

Também pode ser reformulado como

O uso adequado da constpalavra-chave em C` com os prós e os contras da mesma.

Aseem Bansal
fonte
Para aqueles que votam para fechar, explique por que não se enquadra na categoria de Specific issues with software development. Eu estou sendo bem específico.
Aseem Bansal
Suponho que é porque você fez várias perguntas no mesmo post e, portanto, sua pergunta se enquadra na categoria Demasiado amplo: "Existem muitas respostas possíveis ou boas respostas seriam muito longas para esse formato. Adicione detalhes para restringir o conjunto de respostas ou isolar um problema que pode ser respondido em alguns parágrafos ".
21813 Robert Harvey
1
@RobertHarvey Todas essas perguntas são apenas para explicar minha confusão. Minha única pergunta continua sendo o título desta pergunta. Uma boa resposta para isso abrangeria todas essas questões relacionadas. Portanto, permanece um specific issue. O uso adequado da constpalavra-chave em C` com os prós e os contras da mesma.
Aseem Bansal
@RobertHarvey Está melhor agora?
Aseem Bansal

Respostas:

64

Ao revisar o código, aplico as seguintes regras:

  • Sempre use constpara 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 constpara 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 volatileem 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 constapenas 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 constvocê 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 constum 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 strpara const, devemos garantir que isso fuction_btambém leva a const. E assim por diante, se function_bpassa strpara function_cetc. 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 constcódigo existente talvez esteja causando problemas. No entanto, no novo código, é melhor constqualificar - 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';

strchrretorna um char*não a const char*. Como seu parâmetro de chamada, constele 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.

William Morris
fonte
Realmente não tem dois significados. Significa apenas que, como você diz, " Eu estou não vai mudar isso." Por exemplo, é perfeitamente válido ter uma const volatilevariável.
detly
2
Isso vale para os parâmetros de função, mas para constantes no escopo do arquivo, por exemplo, uma constvariável é realmente somente leitura: constdiz "Isso não pode ser modificado". A, const volatilepor outro lado, diz "Isso não pode ser modificado, mas pode mudar". Vou adicionar uma menção aos voláteis na minha resposta.
William Morris
Não discordo do seu comentário, apenas da idéia de que é uma instrução para o compilador colocá-lo na ROM. Isso implica algum tipo de proteção em tempo de execução contra comportamentos indefinidos (por exemplo, modificar uma const de alguma forma), o que pode levar a mal-entendidos como "por que posso alterar essa constvariável por um não- constponteiro" (uma pergunta comum sobre SO e todos os outros fóruns C !). No geral, eu gosto desta resposta:)
detly 14/07/13
Você está certo: "Coloque isso na ROM" é impreciso (embora sucinto :-) - vou alterá-lo para "Isso não pode ser modificado", o que é mais preciso. Obrigado por seus comentários.
William Morris
Esta é uma ótima visão geral. Gosto de dizer que constdeclara dados somente leitura e visualizações somente leitura dos dados - a diferença é "isso não pode ser modificado" versus "você não pode modificar isso".
Jon Purdy
8

Geralmente, em qualquer linguagem de programação é recomendado o uso constou o modificador equivalente, pois

  • Pode esclarecer ao chamador que o que eles passaram não vai mudar
  • Potenciais aprimoramentos de velocidade, já 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
TheLQ
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 para não chamar 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 mesmo o compilador não permitirá que você faça isso. No entanto, você ainda pode alterar facilmente o valor da variável com apenas uma conversão.

No que 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 modificará sua matriz ou estrutura, convém manter a versão original, para criar uma cópia da variável e depois passá-la para a função. Se não for esse o caso, você não precisará da cópia, obviamente, portanto, por exemplo, você pode alterar,

int foo(Structure s);

para

int foo(const Structure * s);

e não ficando a cópia em cima.

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 a. No segundo caso, o ponteiro é constante, mas seu conteúdo não, portanto, o compilador permitirá que você diga * a = 3;sem um erro do compilador, mas não é possível fazer areferência a outra coisa.

lgarcia
fonte
0

De acordo com as declarações da TheLQ:

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

David Otano
fonte