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.

Rating 4.60 out of 5
[?]

2 comentários para “Compatibilidade Binária em C”

  1. C eh poder, e poder eh perigoso!

    A concepcao de que existe uma compatibilidade binaria entre duas estruturas eh algo incrivel que abre a possibilidade de considerarmos o polymorphismo, mas ao mesmo tempo exige que os programadores saibam com que tipo de coisa estao lidando.

    Obviamente a aritmetica de ponteiros e a correcao dos index de acesso aos elementos (de um array ou de uma estrutura) estao diretamente ligadas a plataforma onde a coisa estah sendo executada e ao se desenvolver com este tipo de estrategia em mente eh importante ter BEM claro quais os limites a serem considerados.

    Outro dia ouvi desenvolvedor que C nao era portavel por exemplo, pq voce poderia criar programas que andem por regioes especificas de memoria e isso nao vai funcionar atraves de plataformas/SOs… Clara ma interpretacao tanto do conceito de portabilidade quanto do uso dos mecanismos de acesso a memoria que o C tao elegantemente nos oferece.

    Essa compatibilidade binaria que tu alega tem seus reveses aos quais eh preciso estar atento ao trabalhar… Imagine por exemplo que tu pretenda alocar espaco para trabalhar com estas estruturas… apesar da compatibilidade binaria e do cast te permitir o polymorphismo, ao alocar espaco, tu precisas ter ciencia do tamanho da MAIOR estrutura… Isso em linguagens de nivel superior eh burlado de forma que um array de um determinado objeto nao contem o objeto em si, mas sim uma referencia para ele, o que pode obviamente ser obtido em C com uma array de ponteiros para as structs (o que ao contrario do que muita gente pensa NAO VAI ADICONAR NENHUM IMPACTO DEVIDO A DERREFERENCIA, pois a quantidade de passos para interepretacao eh a mesma que se a struct estivesse de fato na array).

    O ponto eh que, embora esse poder seja amplo e interessante, possibiltando os pontos que tu apontou e muitos outros, o programador ao utilziar este tipo de beneficio, precisa estar ciente de suas implicacoes, e muitos nao estao!

    A origem disso eh a falta de conhecimento da linguagem e o preconceito que alguns programadores tem sobre certos aspectos… seguindo o exemplo do desenvolvedor que questionou sobre a portabilidade de codigo, no meio da conversa ele falou, que um char ocupa 2 Bytes na memoria, o que eh um pressuposto equivocado baseado no estudo de C especifico das plataformas (antigas) da Intel… Para o C, um char e um int ocupam o mesmissimo espaco na memoria, ateh pq nao existe como se enderecar somente parte de uma palavra e portanto seu espaco eh igual a no minimo o tamanho da palavra… obviamente que para quem programa dentro do padrao, isto nao tem nenhum impacto significativo e passa despercebido, mas certamente quem carrega preconceitos como esse vai ter problemas ao tentar alocar espaco para Strings por exemplo, ou vai sofrer com ponteiros selvagens em algum momento, simplesmente pq pressupos alguma coisa que de fato nao condiz com a realidade da plataforma… O triste eh que essas pessoas se acham, baseado nisso, no direito de sair soltando maximas como: “C nao eh portavel!”… Faltou fazer a licao de casa… #fail

    Valeu pelo post Pac, eh muito bom ver alguem resgatando os conceitos que deveriam ser basicos a maioria dos desenvolvedores mas que sao sumariamente ignorados e geram tanta confusao por aih!

  2. Lembrando que esse casting precisa respeitar a ordem, um struct por definicao eh uma estrutura linear na memoria, se voce na classe 2 alterar a ordem dos parametros na declaracao, isso com certeza causaria um erro de casting:

    ex:

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

Deixe um comentário