[Tiago Peczenyj] Compatibilidade Binária em C

Programar em C é sempre divertido, principalmente se vc sabe o que faz. Um exemplo disso é como trabalhar com estruturas de dados complexas, ponteiros e casting.

Imaginem as duas estruturas abaixo:

typedef struct {
	int id;
	char name[128];
} tpessoa;
 
typedef struct {
	int id;
	char name[128];
	char rg[128];
} tpessoafisica;

Ok, tenho um tipo tpessoa e um tpessoafisica que representam um tipo básico (pessoa) e um tipo propositalmente extendido, especializado para algum fim (pessoa fisica). Posso ter um tipo para pessoa juridica, por exemplo.

Imagine que eu posso ter diversas operações com o tipo básico e, por acaso, quero utilizar também com o tipo extendido (tpessoafisica). Como fazer? Em algumas linguagens eu posso fazer isso:

tpessoafisica x = {...};
tpessoa y = (tpessoa) x;

Entretanto em C isso gera um erro de conversion to non-scalar type requested. Eu posso converter int para float, float para int, int para long, char para int, etc, mas conversão de estruturas não é bem por ai: até porque não existe uma clara noção do que deveria acontecer, certo?

Para isso temos que clamar pelo conceito de compatibilidade binária: Sendo duas estruturas de dados, A e B, se B especializa A de forma ter todos os mesmos atributos na ordem que foi definida em A (e, opcionalmente, alguma coisa a mais no final), eu posso fazer um cast de um ponteiro do tipo B para um ponteiro do tipo A.

Vejamos, o tpessoafisica tem no começo os mesmos atributos (id e name) que a tpessoa e, por acaso, tem um atributos rg a mais no final. Dessa forma eu posso fazer o cast dos ponteiros na ordem apropriada.

void mostra_pessoa(tpessoa *x){
	printf("Pessoa { id = %d, name = %s }\n",x->id,x->name);
}
 
int main(){
	tpessoafisica x = {100, "pacman", "666"};
	// cast vale para ponteiros, por isso uso o operador &
	mostra_pessoa((tpessoa *) &x);
	return 0;
}

Ou seja, mostra pessoa esta preparado para receber um ponteiro do tipo tpessoa mas, graças a um habil cast de ponteiros aproveitando o principio de compatibilidade binária eu posso passar o endereço de uma estrutura diferente, no caso de tpessoafisica.

Perceba que eu preciso de um cast entre ponteiros, por isso eu preciso apelar para um & na frente da variavel, pegando o endereço de memória associado aquela variavel. Este recurso é util em muitas situações, desde simular interfaces e herança até coisas mais divertidas como fazer perl 5.x rodar perl 6.