O que significa declarar uma variável volátil?

9

Muitos programas de baixo nível usam a palavra-chave volátil para tipos de mapeamento de memória e coisas do tipo, no entanto, estou meio confuso sobre o que REALMENTE faz em segundo plano. Em outras palavras, o que significa quando o compilador não "otimiza" o endereço de memória?

Vikaton
fonte
11
Se você está lendo a sua idade a partir de uma volatilevariável e diz 5, e você lê-lo novamente no próximo ano, você está garantido para obter 6.
5gon12eder
@ 5gon12eder, entendo que volátil significa que algo está sujeito a mudanças rápidas e fáceis, mas como isso funciona? : S
Vikaton
Além disso, dependendo dos sinalizadores de compilação, uma variável não volátil 'pode' aparecer no depurador (digamos que você esteja usando o código C + Eclipse + gdb, por exemplo), como: 'valor de saída otimizado' porque o valor da variável agora é em algum lugar de um registro. Se você não sabe usar as ferramentas / recursos de depuração da linguagem assembly, basta declarar sua variável usando o modificador volátil.

Respostas:

11

volatile significa que algum outro processador ou dispositivo de E / S ou algo pode alterar a variável de baixo de você.

Com uma variável comum, as etapas do seu programa são a única coisa que irá alterá-lo. Por exemplo, se você ler 5uma variável e não a alterar, ela ainda conterá 5. Como você pode confiar nisso, seu programa não precisa gastar tempo para ler a variável novamente na próxima vez que você quiser usá-la. O compilador C ++ é inteligente para gerar código que apenas se lembra do 5.

Mas você pode ler como 5, então talvez o sistema carregue dados do disco na memória, alterando-os para 500. Se você deseja que seu programa leia o valor novo 500, é necessário que o compilador não seja muito inteligente sobre o uso da leitura anterior 5. Você precisa dizer a ele para recarregar o valor toda vez. Isso é o que volatilefaz.

Uma analogia para crianças de 5 anos
Digamos que você coloque uma grande folha de papel em uma mesa. Em um canto do papel, você anota a pontuação atual de um jogo em andamento 3 to 4,. Então você vai para o lado oposto da mesa e começa a escrever uma história sobre o jogo. Seu amigo que está assistindo o jogo atualiza a pontuação naquele canto à medida que o jogo avança. Ela apaga 3 to 4e escreve 3 to 5.

Quando você coloca a pontuação do jogo em sua história, você pode:

  1. Anote a última pontuação que leu, 3 to 4assumindo alegremente que não mudou (ou não se importando se mudou) ou
  2. Ande pelo lado oposto da tabela para ler a pontuação atual (que 3 to 5agora é a atual) e volte. É assim que uma volatilevariável age.
Jerry101
fonte
11

volatile significa duas coisas:

  1. O valor da variável pode mudar sem que nenhum código seu a altere. Portanto, sempre que o compilador lê o valor da variável, ele não pode assumir que é o mesmo da última vez que foi lido ou que é o mesmo que o último valor armazenado, mas deve ser lido novamente.

  2. O ato de armazenar um valor em uma variável volátil é um "efeito colateral" que pode ser observado de fora; portanto, o compilador não tem permissão para remover o ato de armazenar um valor; por exemplo, se dois valores são armazenados em uma linha, o compilador deve realmente armazenar o valor duas vezes.

Como um exemplo:

i = 2; 
i = i; 

O compilador deve armazenar o número dois, ler a variável i, armazenar a variável em que leu.

Existe outra situação: se uma função usa setjmpe depois longjmpé chamada, é garantido que todas as variáveis ​​locais voláteis da função tenham o último valor armazenado - esse não é o caso de variáveis ​​locais não voláteis.

gnasher729
fonte
Existem alguns problemas sutis aqui. Um problema sutil é que você caracterizou leituras voláteis como uma característica da variável, quando na verdade elas são uma característica de como a variável é acessada . Se tivermos a variável ie o valor pi = &i, x = *pia leitura será feita i, mas não é garantido que essa leitura tenha semântica volátil.
Eric Lippert
11
@ EricLippert: Se ié declarado como volatile int ientão pideve ser declarado como volatile int *pi, nesse caso, *pié um acesso volátil, não?
Jon Purdy
2

Explicação abstrata
C e C ++ têm o conceito de uma máquina abstrata . Quando o código usa o valor de alguma variável, a máquina abstrata diz que a implementação precisa acessar o valor dessa variável. O código do formulário statement_A; statement_B; statement_C;deve ser executado exatamente na ordem especificada. Expressões comuns a essas três instruções devem ser recalculadas sempre que ocorrerem.

Pelas máquinas abstratas, dada a sequência de instruções statement_A; statement_B; statement_C;, a implementação deve primeiro executar statement_Aem sua totalidade, depois statement_Be finalmente statement_C. A implementação não se lembra de que você atribuiu ageo valor 5. Toda declaração que referencia agedeve acessar o valor dessa variável.

Não haveria necessidade da volatilepalavra - chave se as implementações executassem estritamente o código C ou C ++ de acordo com as especificações abstratas da máquina. As máquinas abstratas C e C ++ não têm conceito de registradores, subexpressões comuns e a ordem de execução é rigorosa.

Ambos os idiomas também têm regras como se . Uma implementação é compatível com o padrão desde que ela se comporte como se tivesse executado coisas de acordo com a especificação abstrata da máquina. O compilador pode assumir que variáveis ​​não voláteis não alteram valores entre atribuições. Desde que não quebre a as-ifregra, a sequência statement_A; statement_B; statement_C;pode ser implementada executando parte de statement_C, depois parte de statement_A, depois todo statement_B, depois o restante statement_Ae, finalmente, o restante statement_C.

Essas regras como se não se aplicam a volatilevariáveis. No que diz respeito às volatilevariáveis ​​e funções, uma implementação precisa fazer exatamente o que você pediu e exatamente na ordem em que você disse para fazer as coisas.

Há uma desvantagem na especificação abstrata da máquina: é lenta. Um aspecto positivo de C e C ++ em comparação com outras linguagens é que elas são bastante rápidas. Este não seria o caso se o código fosse executado por essas máquinas abstratas. Os COMO SE regras são o que permitirá C e C ++ para ser tão rápido.

Resposta ELI5

o que significa quando o compilador não "otimiza" o endereço de memória?

"Otimizar" um endereço de memória é um conceito avançado, algo que não se enquadra nas capacidades de uma criança de cinco anos. As crianças de cinco anos em conformidade farão exatamente o que você manda, nem mais nem menos. Com volatile, você está dizendo à implementação para agir como se fosse cinco: sem pensar, sem otimizações sofisticadas. Em vez disso, a implementação precisa fazer exatamente o que o código diz.

David Hammen
fonte
1

(non-) volatile é uma dica para o compilador como otimizar o código (do ponto de vista do código de montagem gerado):

  • não volátil significa que seu compilador atual decide onde a variável será localizada ou como o valor da variável-s é transferido para uma sub-rotina
    • em um endereço de memória fixo,
    • na pilha [relativa ao atual stackpointer do processador],
    • no heap [relativo ao atual basepointer do processador],
    • em um registro do processador,
    • ...
  • volátil significa que o compilador não pode otimizar a variável, porque algo fora do controle main-cpu-s (ou seja, um io-processador separado) pode alterar esse valor.
k3b
fonte
0

As respostas parecem bastante consistentes, mas faltam um ponto importante. Você está dizendo ao compilador que deseja alocar espaço e, para cada acesso, leia OR WRITE, deseja que ele execute esse acesso. Não queremos que ele otimize esses acessos ou essa variável por algum motivo.

Sim, uma razão é porque outra pessoa pode alterar esse valor para nós. Outro motivo é que podemos estar alterando esse valor para outra pessoa. Que outra pessoa, que a modifique para nós ou para a qual estamos modificando, pode ser hardware / lógica ou software. É frequentemente usado para definir acessos para controle e registros de status em programas embarcados bare metal, gravando ou lendo no hardware. Bem como o software conversando com o software explicado em outras respostas.

Você também verá o volátil usado para controlar quando e em que ordem os acessos ocorrem, se você estiver tentando cronometrar uma seção do código e não usar voláteis as variáveis ​​em questão (horário de início, horário de término e diferença). computado próximo ao final, o compilador é livre para mover qualquer uma das medições de tempo (e não onde as colocamos), não que ele não seja volátil, mas a experiência mostra menos probabilidade.

Na ocasião, você verá que ele costumava queimar tempo, um pisca-pisca elementar, o olá mundo do bare metal, pode usar um volátil para uma variável que conta com um grande número apenas para queimar tempo para o olho humano ver o led mudar estado. Exemplos mais avançados que o uso de temporizadores ou outros eventos para queimar o tempo.

old_timer
fonte