Apelidando um ponteiro

O problema do código do post anterior (aqui) é que podemos fazer a chamada assim:

vec3_cross(&v1, &v1, &v2);  /* v1 = v1 x v2; */

O que causa o cálculo errado do produto vetorial. Considere os vetores v1(1,0,0) e v2(0,1,0). O produto vetorial deveria ser vout(0,0,1), mas:

v1.x = (v1.y * v2.z) - (v1.z * v2.y) = 0 - 0 = 0;
v1.y = (v1.z * v2.x) - (v1.x * v2.z) = 0 - 0 = 0;
v1.z = (v1.x * v2.y) - (v1.y * v2.x) = 0 - 0 = 0;

O vetor (0,0,0) definitivamente não é perpendicular aos vetores unitários (1,0,0) e (0,1,0)! Note que v1.x e v1.y são alterados e usados no restante da função! O problema é que estamos assumindo que os 3 ponteiros são diferentes, isto é, apontam para regiões diferentes da memória, mas vout_p, v1_p e v2_p são apenas “apelidos” (aliases) para os ponteiros reais, passados para a função.

Quando você faz algo assim:

int x;

/* inicializa x em algum lugar */

x = x + 1;

A última expressão trabalha com uma cópia temporária da variável x, do lado direito, antes de atribuí-la ao próprio x, do lado esquerdo. É claro que o compilador otimizará essa lógica, mas essa é a essência da coisa (inclusive, este é um dos motivos da existência do construtor de cópia, nas classes em C++). No caso da minha rotina, precisamos criar um vetor temporário antes de atribuí-lo para o conteúdo de vout_p, evitando o problema do “apelido dos ponteiros”:

void vec3_cross(vec3_t *vout_p, vec3_t *v1_p, vec3_t *v2_p)
{
  vec3_t vtemp;

  vtemp.x = (v1_p->y * v2_p->z) - (v1_p->z * v2_p->y);
  vtemp.y = (v1_p->z * v2_p->x) - (v1_p->x * v2_p->z);
  vtemp.z = (v1_p->x * v2_p->y) - (v1_p->y * v2_p->x);

  vec3_copy(vout_p, &vtemp);
}

Onde vec3_copy é simplesmenete:

void vec3_copy(vec3_t *vout_p, vec3_t *vin_p)
{
  vout_p->x = vin_p->x;
  vout_p->y = vin_p->y;
  vout_p->z = vin_p->z;
}

Então, meus amigos, cuidado com o ponter aliasing, ok?

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