O comportamento indefinido ocorre quando o programa irá causar comportamento indefinido, não importa o que aconteça a seguir. No entanto, você deu o seguinte exemplo.
int num = ReadNumberFromConsole();
if (num == 3) {
PrintToConsole(num);
*((char*)NULL) = 0; //undefined behavior
}
A menos que o compilador conheça a definição de PrintToConsole
, ele não pode remover if (num == 3)
condicional. Vamos supor que você tenha o LongAndCamelCaseStdio.h
cabeçalho do sistema com a seguinte declaração de PrintToConsole
.
void PrintToConsole(int);
Nada muito útil, certo. Agora, vamos ver o quão mau (ou talvez não tão mau, o comportamento indefinido poderia ser pior) o fornecedor é, verificando a definição real desta função.
int printf(const char *, ...);
void exit(int);
void PrintToConsole(int num) {
printf("%d\n", num);
exit(0);
}
Na verdade, o compilador tem que assumir que qualquer função arbitrária que o compilador não sabe o que faz pode sair ou lançar uma exceção (no caso do C ++). Você pode notar que *((char*)NULL) = 0;
não será executado, pois a execução não continuará após a PrintToConsole
chamada.
O comportamento indefinido ataca quando PrintToConsole
realmente retorna. O compilador espera que isso não aconteça (pois isso faria com que o programa executasse um comportamento indefinido, não importa o que acontecesse), portanto, tudo pode acontecer.
No entanto, vamos considerar outra coisa. Digamos que estejamos fazendo uma verificação de nulos e use a variável após a verificação de nulos.
int putchar(int);
const char *warning;
void lol_null_check(const char *pointer) {
if (!pointer) {
warning = "pointer is null";
}
putchar(*pointer);
}
Nesse caso, é fácil perceber que lol_null_check
requer um ponteiro não NULL. A atribuição à warning
variável global não volátil não é algo que poderia sair do programa ou lançar qualquer exceção. O pointer
também não é volátil, portanto, não pode mudar magicamente seu valor no meio da função (se mudar, é um comportamento indefinido). A chamada lol_null_check(NULL)
irá causar um comportamento indefinido que pode fazer com que a variável não seja atribuída (porque neste ponto, o fato de que o programa executa o comportamento indefinido é conhecido).
No entanto, o comportamento indefinido significa que o programa pode fazer qualquer coisa. Portanto, nada impede o comportamento indefinido de voltar no tempo e travar seu programa antes da int main()
execução da primeira linha . É um comportamento indefinido, não precisa fazer sentido. Pode muito bem travar após digitar 3, mas o comportamento indefinido voltará no tempo e travará antes mesmo de você digitar 3. E quem sabe, talvez o comportamento indefinido substituirá a RAM do sistema e fará com que o sistema trave 2 semanas depois, enquanto seu programa indefinido não está em execução.