Comportamento indefinido? Fuja sempre dele!

Num de meus posts, no facebook, mostrei um “códigozinho” interessante contendo a expressão “2<x<2”, que é perfeitamente válida em C. No exemplo o conteúdo de ‘x’ era desconhecido porque a variável foi declarada, mas jamais definida:

int f(void) { int x; return 2 < x < 2; }

Mesmo que ‘x’ tivesse sido definido, o resultado sempre será 0!

Mas, eis um código realmente esquisito:

#include <stdio.h>

int f(int flag)
{
  int x;

  if (flag)
    x = 7;

  if (7 == x)
    puts("ok");
}

Eis as duas listagens em assembly da função: Uma com otimização máxima (-O3) e outra sem otimizações (-O0):

; Compilado com -O0 -fomit-frame-pointer
f:
  sub rsp,40
  mov [rsp+12],edi
  cmp dword ptr [rsp+12],0
  je  .L2
  mov dword ptr [rsp+28],7
.L2:
  cmp dword ptr [rsp+28],7
  jne .L1
  mov edi,offset .LC0        ; LC0 é o símbolo onde está a string.</span>
  call puts
.L1:
  add rsp,40
  ret

;-----%<----- corte aqui -----%<-----
; Compilado com -O3 -fomit-frame-pointer
f:
  mov edi,offset .LC0        ; LC0 é o símbolo onde está a string.</span>
  jmp puts

O código gerado sem otimizações parece ser o esperado, mas o otimizado simplesmente jogou todos os “ifs” no lixo… Hã? Como assim?

Isso não torna o GCC menos confiável porque o que fizemos foi o que a especificação da linguagem chama de comportamento indefinido (undefined behavior). Usar uma variável não inicializada numa expressão causa um comportamento não definido e o compilador é livre para decidir o que fazer, mesmo que não te pareça “lógico”.

Outros exemplos de comportamento indefinido:

a[i] = i++;

/* Qual posição do array será modificada com qual valor? */
printf("%d, %d\n", ++n, f(n));  /* Qual será o 'n' passado para f()? */
x = y >> 1;  /* Se 'y' é 'int' e é negativo, qual será o valor de 'x'? */

FUJA dos comportamentos indefinidos… estude a especificação da linguagem…

Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s