quinta-feira, 15 de setembro de 2011

Um jeito diferente de indexar arrays - não façam isso em casa!

O que você diria se encontrasse a seguinte linha de código no meio de um grande sistema que vc está trabalhando:

3[array] = x;

Alguns vão pensar que se trata de um erro de digitação bem estranho e que o modulo não está compilando, ai vão checar o Makefile, depois vão checar se não existe algum cache de código ativo, depois vão checar o repositório e começar a culpar o CVS, os defensores do GIT vão mostrar como CVS é uma coisa capenga... todos vão checar forums e depois de uma flamewar saudável vão começar a culpar o compilador, o SO, os ETs e vão acabar consultando um padre novo e um padre velho... A questão é que esta linha é válida e funcional! A sintaxe usada para indexar arrays em C é uma "maquiagem" que esconde a aritmética de ponteiros que acontece. A nível de código assembly, ponteiros e inteiros são praticamente a mesma coisa. Sendo assim a[b] diz algo como: some a com b, o resultado deve ser visto como um endereço de memória. Se a expressão estiver do lado esquerdo então é para escrever neste local de memória, se estiver do lado direito deve ler desse endereço, ou seja, deve desreferenciar o resultado como se fosse um ponteiro. Essa expressão será vista como, *(a + b) ou *(b + a). Como a adição é comutativa, a + b == b + a, daí a[b] == b[a]. A unica restrição sintatica nesse caso é: a ou b deve ser um ponteiro e o outro um inteiro. Isso funciona mesmo se um dos operandos é uma constante inteira, como o 3[array]. É este mesmo mecanismo que nos permite usar índices negativos em um array sem nenhum problema, veja:

int main()
{
int * p;
int a[10];
int i,j;

a[4]=42;
a[5]=4;

p = &a[5];

i = *p;
j = p[-1];

printf("%d %d\n",i,j);

return 0;
}

Este código imprime "4 42". Note que p[-1] vai se transformar em *(p+(-1)) -> *(p-1). Lembre que *(p+3) não significa, necessáriamente, que o resultado é o byte de endereço P+3, o operando que não é ponteiro, no caso 3, vai ser escalado pelo tamanho do tipo que p aponta, então se p aponta para um int a conta, para criar o código asm, é (endereço(p) + (3*sizeof(int)). Só não tente isso no trabalho ;) Mas se for tentar, aproveite e use com arrays de mais de uma dimenção:

int main()
{
int i;
int a[2][2];
int x,y;
x = 0;
y = !x;

a[0][1]=42;

i = y[x[a]];

printf("%d\n",i);

return 0;
}

WhuHAUWhauwhauwhauw Se for fazer, faça direito, ahm?!?! Cya!!!

Um comentário:

Lucas Martins disse...

kkk
Muito interessante a postagem!
Obrigado pelo ensinamento!
Abraços.