Em C, uma variável const pode ser modificada por meio de um ponteiro?

Eu escrevi algo parecido com isso no meu código

const int x=1; int *ptr; ptr = &x; *ptr = 2; 

Isso funciona em todos os compiladores? Por que o compilador do GCC não percebe que estamos mudando uma variável constante?

const realmente não significa “constante”. Algo que é “constante” em C tem um valor determinado em tempo de compilation; um literal 42 é um exemplo. A palavra-chave const realmente significa somente leitura. Considere, por exemplo:

 const int r = rand(); 

O valor de r não é determinado até o tempo de execução do programa, mas a palavra-chave const significa que você não tem permissão para modificar r depois de ter sido inicializado.

Em seu código:

 const int x=1; int *ptr; ptr = &x; *ptr = 2; 

a atribuição ptr = &x; é uma violação de restrição , o que significa que um compilador em conformidade é necessário para reclamar sobre isso; você não pode legalmente atribuir um valor const int* (ponteiro para const int) a um object não-const int* . Se o compilador gerar um executável (o que ele não precisa fazer; pode rejeitá-lo), o comportamento não é definido pelo padrão C.

Por exemplo, o código gerado pode na verdade armazenar o valor 2 em x – mas uma referência posterior a x pode produzir o valor 1 , porque o compilador sabe que x não pode ter sido modificado após sua boot. E sabe disso porque você disse isso, definindo x como const . Se você mentir para o compilador, as conseqüências podem ser arbitrariamente ruins.

Na verdade, a pior coisa que pode acontecer é que o programa se comporte como você espera; Isso significa que você tem um bug muito difícil de detectar. (Mas o diagnóstico que você deveria ter obtido será uma grande dica.)

Esboço on-line C 2011 :

6.7.3 Qualificadores de Tipo


6 Se for feita uma tentativa de modificar um object de fi nido com um tipo consti-quali fi cado através do uso de um lvalor com o tipo não-const-quali fi cado, o comportamento é indefinido . Se for feita uma tentativa de se referir a um object definido com um tipo de qualificação volátil através do uso de um lvalor com o tipo quali fi cado não volátil, o comportamento é indefinido. 133)


133) Isso se aplica aos objects que se comportam como se fossem definidos com tipos qualificados, mesmo que nunca sejam de fi nidos como objects no programa (como um object em um endereço de input / saída mapeado pela memory).

Enfase adicionada.

Como o comportamento é deixado indefinido, o compilador não é obrigado a emitir um diagnóstico, nem é necessário parar a tradução. Isso seria difícil de entender no caso geral; suponha que você tivesse uma function como

 void foo( int *p ) { *p = ...; } 

definido em sua própria unidade de tradução separada. Durante a tradução, o compilador não tem como saber se p poderia estar apontando para um object com ou sem const . Se a sua chamada é algo como

 const int x; foo( &x ); 

você pode receber um aviso como o parameter 1 of 'foo' discards qualifiers ou algo similarmente esclarecedor.

Observe também que o qualificador const não significa necessariamente que a variável associada será armazenada na memory somente leitura; portanto, é possível que o código acima “funcione” (atualize o valor em x ) em que você atualizou com êxito x por fazendo uma corrida final em torno da semântica const . Mas então você pode simplesmente não declarar x como const .

Mau programador. Nenhuma torta da lua!

Se você precisar modificar uma const, copie-a para uma variável não-const e trabalhe com ela. É const por um motivo. Tentando “sneak” em torno de um const pode causar sérios problemas de tempo de execução. ou seja, o otimizador provavelmente usou o valor inline, etc.

 const int x=1; int non_const_x = x; non_const_x = 2; 

Há uma boa discussão sobre isso aqui: o casting maligno é superado pelo compilador do mal?

Eu esperaria que o gcc compilasse isso porque:

  • ptr é permitido apontar para x, caso contrário, a leitura seria impossível, embora como o comentário abaixo diz que não é exatamente um código shiny e o compilador deve reclamar. As opções de aviso afetarão (ou não) se ele foi ou não avisado.
  • quando você escreve para x, o compilador não mais “sabe” que está escrevendo para um const, tudo isso está nas mãos dos codificadores em C. No entanto, ele realmente sabe, então pode avisá-lo, dependendo das opções de aviso você selecionou.

quer ele funcione ou não, no entanto, dependerá de como o código é compilado, da maneira como const é implementado para as opções de compilation selecionadas e da CPU e arquitetura de destino. Isso pode funcionar. Ou pode falhar. Ou você pode escrever em um bit “random” de memory e causar (ou não) algum efeito esquisito. Não é uma boa estratégia de codificação, mas essa não foi sua pergunta 🙂