A principal resposta é um equívoco errado (mas comum):
O comportamento indefinido é uma propriedade de tempo de execução *. Ele NÃO PODE "viagem no tempo"!
Certas operações são definidas (pelo padrão) para ter efeitos colaterais e não podem ser otimizadas. As operações que fazem E / S ou que acessam volatile
variáveis se enquadram nesta categoria.
No entanto , há uma advertência: UB pode ser qualquer comportamento, incluindo comportamento que desfaça operações anteriores. Isso pode ter consequências semelhantes, em alguns casos, à otimização do código anterior.
Na verdade, isso é consistente com a citação na resposta principal (ênfase minha):
Uma implementação conforme executando um programa bem formado deve produzir o mesmo comportamento observável que uma das execuções possíveis da instância correspondente da máquina abstrata com o mesmo programa e a mesma entrada.
No entanto, se qualquer uma dessas execuções contiver uma operação indefinida, esta Norma Internacional não impõe nenhum requisito à implementação que executa esse programa com aquela entrada (nem mesmo em relação às operações anteriores à primeira operação indefinida).
Sim, esta citação faz dizer "nem mesmo no que diz respeito a operações anteriores à primeira operação indefinido" , mas aviso que este é especificamente sobre o código que está sendo executado , não apenas compilado.
Afinal, o comportamento indefinido que não é realmente alcançado não faz nada, e para que a linha que contém o UB seja realmente alcançada, o código que o precede deve ser executado primeiro!
Então, sim, uma vez que o UB é executado , quaisquer efeitos das operações anteriores se tornam indefinidos. Mas até que isso aconteça, a execução do programa está bem definida.
Observe, no entanto, que todas as execuções do programa que resultam nisso podem ser otimizadas para programas equivalentes , incluindo qualquer um que execute operações anteriores, mas depois desfaça seus efeitos. Consequentemente, o código anterior pode ser otimizado sempre que isso for equivalente a seus efeitos serem desfeitos ; caso contrário, não pode. Veja abaixo um exemplo.
* Nota: Isso não é inconsistente com o UB ocorrendo em tempo de compilação . Se o compilador pode realmente provar que o código UB vai sempre ser executadas para todas as entradas, então UB pode estender-se a tempo de compilação. No entanto, isso requer saber que todo o código anterior eventualmente retorna , o que é um requisito forte. Novamente, veja abaixo um exemplo / explicação.
Para tornar isso concreto, observe que o código a seguir deve ser impresso foo
e aguardar sua entrada, independentemente de qualquer comportamento indefinido que o segue:
printf("foo");
getchar();
*(char*)1 = 1;
No entanto, também observe que não há garantia de que foo
permanecerá na tela após a ocorrência do UB, ou que o caractere digitado não estará mais no buffer de entrada; ambas as operações podem ser "desfeitas", o que tem um efeito semelhante à "viagem no tempo" do UB.
Se a getchar()
linha não estivesse lá, seria legal que as linhas fossem otimizadas se e somente se isso fosse indistinguível da saída foo
e, em seguida, "desfazendo".
Se os dois seriam indistinguíveis ou não, dependeria inteiramente da implementação (ou seja, do seu compilador e da biblioteca padrão). Por exemplo, você pode printf
bloquear seu thread aqui enquanto espera que outro programa leia a saída? Ou vai voltar imediatamente?
Se ele pode bloquear aqui, então outro programa pode se recusar a ler sua saída completa e pode nunca retornar e, conseqüentemente, UB pode nunca realmente ocorrer.
Se ele pode retornar imediatamente aqui, então sabemos que ele deve retornar e, portanto, otimizá-lo é totalmente indistinguível de executá-lo e desfazer seus efeitos.
Obviamente, como o compilador sabe qual comportamento é permitido para sua versão específica do printf
, ele pode otimizar de acordo e, conseqüentemente, printf
pode ser otimizado em alguns casos e não em outros. Mas, novamente, a justificativa é que isso seria indistinguível das operações anteriores de desfazer do UB, não que o código anterior esteja "envenenado" por causa do UB.
a
a