Diferença entre const e const volátil

Se declararmos uma variável como volatile toda vez que o valor novo for atualizado
Se declararmos uma variável como const então o valor dessa variável não será alterado

Então const volatile int temp;
Qual é o uso de declarar a variável temp como acima?
O que acontece se declararmos como const int temp ?

Um object marcado como const volatile não terá permissão para ser alterado pelo código (um erro será gerado devido ao qualificador const ) – pelo menos através desse nome / ponteiro específico.

A parte volatile do qualificador significa que o compilador não pode otimizar ou reordenar o access ao object.

Em um sistema embarcado, isso é normalmente usado para acessar registros de hardware que podem ser lidos e atualizados pelo hardware, mas não faz sentido escrever (ou pode ser um erro para gravar).

Um exemplo pode ser o registro de status de uma porta serial. Vários bits indicarão se um caractere está aguardando para ser lido ou se o registrador de transmissão está pronto para aceitar um novo caractere (ou seja, está vazio). Cada leitura desse registro de status pode resultar em um valor diferente, dependendo do que ocorreu no hardware da porta serial.

Não faz sentido escrever para o registrador de status (dependendo da especificação específica do hardware), mas é necessário certificar-se de que cada leitura do registrador resulte em uma leitura real do hardware – usando um valor em cache de uma leitura anterior. t informa sobre alterações no estado do hardware.

Um exemplo rápido:

 unsigned int const volatile *status_reg; // assume these are assigned to point to the unsigned char const volatile *recv_reg; // correct hardware addresses #define UART_CHAR_READY 0x00000001 int get_next_char() { while ((*status_reg & UART_CHAR_READY) == 0) { // do nothing but spin } return *recv_reg; } 

Se esses pointers não foram marcados como sendo volatile , alguns problemas podem ocorrer:

  • o teste de loop while pode ler o registrador de status apenas uma vez, já que o compilador poderia assumir que qualquer coisa que ele apontasse nunca mudaria (não há nada no loop ou no loop while que possa alterá-lo). Se você inseriu a function quando não havia nenhum caractere esperando no hardware UART, você pode acabar em um loop infinito que nunca parou mesmo quando um caractere foi recebido.
  • a leitura do registrador de recepção pode ser movida pelo compilador para antes do loop while – novamente, porque não há nada na function que indique que *recv_reg é alterado pelo loop, não há razão para que ele não possa ser lido antes de entrar no loop.

Os qualificadores volatile garantem que essas otimizações não sejam executadas pelo compilador.

  • volatile irá dizer ao compilador para não otimizar o código relacionado a variável, geralmente quando sabemos que pode ser alterado de “fora”, por exemplo, por outro segmento.
  • const dirá ao compilador que é proibido ao programa modificar o valor da variável.
  • const volatile é uma coisa muito especial que você provavelmente verá usado exatamente 0 vezes em sua vida ™. Como é de se esperar, isso significa que o programa não pode modificar o valor da variável, mas o valor pode ser modificado a partir do exterior, portanto, nenhuma otimização será executada na variável.

Não é porque a variável é const que pode não ter mudado entre dois pontos de sequência.

Constness é uma promise que você faz para não mudar o valor, não que o valor não seja alterado.

Eu precisei usar isso em um aplicativo incorporado em que algumas variables ​​de configuração estão localizadas em uma área de memory flash que pode ser atualizada por um gerenciador de boot. Estas variables ​​de configuração são ‘constantes’ durante o tempo de execução, mas sem o qualificador volátil o compilador otimizaria algo assim …

 cantx.id = 0x10<<24 | CANID<<12 | 0; 

... pré-computando o valor constante e usando uma instrução de assembly imediata, ou carregando a constante a partir de um local próximo, de forma que qualquer atualização do valor do CANID original na área do flash de configuração seja ignorada. O CANID tem que ser volátil.

Em C, const e volátil são qualificadores de tipo e esses dois são independentes.

Basicamente, const significa que o valor não é modificável pelo programa.

E volátil significa que o valor está sujeito a uma mudança repentina (possivelmente de fora do programa).

Na verdade, o padrão C menciona um exemplo de declaração válida que é tanto const quanto volátil. O exemplo é

“Extern const volatile int real_time_clock;”

onde real_time_clock pode ser modificável por hardware, mas não pode ser atribuído, incrementado ou decrementado.

Portanto, já devemos tratar const e volátil separadamente. Além disso, esse qualificador de tipo também se aplica a struct, union, enum e typedef.

const significa que a variável não pode ser modificada pelo código c, não que não possa ser alterada. Isso significa que nenhuma instrução pode gravar na variável, mas seu valor ainda pode mudar.

volatile significa que a variável pode mudar a qualquer momento e, portanto, nenhum valor armazenado em cache pode ser usado; cada access à variável deve ser executado em seu endereço de memory.

Como a questão é marcada como “incorporada” e supondo que temp seja uma variável declarada pelo usuário, não um registro relacionado ao hardware (uma vez que eles são normalmente tratados em um arquivo .h separado), considere:

Um processador incorporado que possui memory de dados de leitura / gravação volátil (RAM) e memory de dados não volátil somente leitura, por exemplo, memory FLASH na arquitetura von-Neumann, onde dados e espaço de programa compartilham um barramento de dados e endereços comum.

Se você declarar const temp para ter um valor (pelo menos se for diferente de 0), o compilador atribuirá a variável a um endereço no espaço FLASH, porque mesmo que ele seja atribuído a um endereço RAM, ele ainda precisa de memory FLASH para armazenar o valor inicial da variável, tornando o endereço RAM um desperdício de espaço, uma vez que todas as operações são somente leitura.

Em consequência:

int temp; é uma variável armazenada na RAM, inicializada em 0 na boot (cstart), valores em cache podem ser usados.

const int temp; é uma variável armazenada em (read-ony) FLASH, inicializada em 0 no tempo do compilador, valores em cache podem ser usados.

volatile int temp; é uma variável armazenada na RAM, inicializada em 0 na boot (cstart), os valores armazenados em cache NÃO serão usados.

const volatile int temp; é uma variável armazenada em (read-ony) FLASH, inicializada em 0 no tempo do compilador, os valores armazenados em cache NÃO serão usados

Aí vem a parte útil:

Atualmente, a maioria dos processadores embarcados tem a capacidade de fazer alterações em sua memory não volátil somente leitura por meio de um módulo de function especial, em cujo caso a const int temp pode ser alterada em tempo de execução, não diretamente. Dito de outra maneira, uma function pode modificar o valor no endereço onde a temp é armazenada.

Um exemplo prático seria usar temp para o número de série do dispositivo. A primeira vez que o processador incorporado é executado, temp será igual a 0 (ou o valor declarado) e uma function poderá usar esse fato para executar um teste durante a produção e, se tiver êxito, solicitar a atribuição de um número de série e modificar o valor de temp por meio de uma function especial. Alguns processadores têm um intervalo de endereço especial com memory OTP (programável de uma só vez) apenas para isso.

Mas aqui vem a diferença:

Se const int temp é um ID modificável em vez de um número serial programável e NÃO é declarado volatile , um valor em cache pode ser usado até a próxima boot, o que significa que o novo ID pode não ser válido até a próxima reboot, ou mesmo pior, algumas funções podem usar o novo valor, enquanto outras podem usar um valor em cache mais antigo até a reboot. Se const int temp declarado voltaile , a mudança de ID entrará em vigor imediatamente.

Este artigo discute os cenários onde você deseja combinar qualificadores constantes e voláteis.

http://embeddedgurus.com/barr-code/2012/01/combining-cs-volatile-and-const-keywords/

Você pode usar const e volátil juntos. Por exemplo, se 0x30 for considerado o valor de uma porta que é alterada apenas por condições externas, a seguinte declaração evitaria qualquer possibilidade de efeitos colaterais acidentais:

 const volatile char *port = (const volatile char *)0x30; 

Usamos a palavra-chave ‘const’ para uma variável quando não queremos que o programa a altere. Ao passo que quando declaramos uma variável ‘const volatile’ estamos dizendo ao programa para não alterá-lo e ao compilador que essa variável pode ser alterada inesperadamente a partir da input vinda do mundo externo.

Em termos simples, o valor na variável ‘const volatile’ não pode ser modificado programaticamente, mas pode ser modificado pelo hardware. Volátil aqui é para evitar qualquer otimização de compilador.