Primeiro de tudo, eu sei que isso é UB e, tecnicamente, qualquer coisa pode acontecer. Mas, em relação a esse trecho de código compilado com -O0 para o alvo x86_64-linux-gnu, por que isso nunca imprime "truthy"?
#include <stdio.h>
#include <stdbool.h>
int test(void)
{
bool value;
if (value)
{
printf("truthy");
}
printf("Value: %d", value);
}
int main(void)
{
double buffer[80000];
buffer[10] = 0;
test();
}
Eu esperaria que o valor fosse basicamente aleatório. O que estou esquecendo?
EDIT: Estou falando de C aqui, mas se houver alguma diferença com C++, também estou interessado nela.
Quando o padrão C diz que o comportamento é indefinido, significa apenas que o padrão C não especifica nada sobre o comportamento. Em particular, ele não diz nada sobre se algo mais especifica ou afeta o comportamento.
A ausência de uma declaração sobre o que algo faz não é uma razão válida para inferir que seria aleatório.
Em sistemas multiusuário de propósito geral, quando um processo solicita memória, ela é geralmente fornecida de duas maneiras (talvez exceto solicitações especiais): Para código ou dados inicializados, ele é lido do arquivo executável do programa para a memória. Para dados não inicializados, o sistema operacional geralmente não pode fornecer memória não inicializada. Isso ocorre porque a memória é compartilhada por processos: ela é usada por um processo e depois por outro processo. O sistema operacional tem a obrigação de manter os dados dos processos confidenciais (a menos que eles solicitem especificamente o compartilhamento de memória). Portanto, sempre que o sistema operacional fornece memória a um processo, ele deve inicializá-la para dados não sensíveis. Isso é feito com mais frequência definindo tudo como zero.
Então, quando um processo começa em tal sistema, a memória usada para sua pilha e para outros dados não inicializados conterá, na verdade, zeros. Quando um programa C começa, há algum código de inicialização que é executado antes da
main
rotina. Esse código pode usar parte da pilha para seus próprios propósitos, então, quandomain
é chamado depois desse código inicial, nem tudo na pilha será zero. Então, se você tentar observar os valores de objetos não inicializados na pilha no início do seu programa, você pode ver que alguns deles têm valores diferentes de zero, mas valores zero serão muito comuns.Mais adiante no seu programa, depois que várias rotinas forem chamadas e retornadas, sua pilha terá sido usada para vários propósitos, deixando para trás uma variedade de dados, e é menos provável que objetos não inicializados na pilha pareçam ter valores zero.
Esta é uma lição importante: embora o padrão C não especifique o comportamento aqui, o comportamento é afetado pelos requisitos do sistema operacional, por como o ambiente C é implementado e por outros fatores. Geralmente não é aleatório; é em grande parte uma consequência de coisas que podemos aprender.