Objetos em Linguagem C

No desenvolvimento de software embarcado em microcontroladores mais simples (e com compiladores mais simples), as vezes nos deparamos com uma situação complicada: não podemos utilizar um recurso avançado de software na plataforma-alvo e, por isso, somos forçados a pensar em soluções custosas, sejam em tempo de implementação ou em alocação de recursos do microcontrolador.

 

Uma das situações em que isso ocorre é o uso / abordagem de objetos em microcontroladores com compiladores mais limitados: para algumas soluções, seria muito interessante encapsular variáveis diversas e funções em um só elemento, mas o compilador não suporta C++ e seus recursos de orientação a objeto. Neste artigo, será apresentada uma maneira de se criar objetos em linguagem C puro, objetivando seu uso em microcontroladores e compiladores mais limitados.

 

 

Contexto

 

Embora hoje em dia a grande maioria dos compiladores dê suporte à linguagem C++, isso não era verdade no passado. Devido ao mundo ser "muito apertado" (pouquíssimos recursos), nós desenvolvedores éramos obrigados a tomar estratégias de software que passavam muito longe dos benefícios de uma orientação a objetos. Como produtos e equipamentos desenvolvidos naquela época podem estar em operação (e até mesmo fabricação) até hoje, as empresas precisam dar suporte a eles. Portanto, embora o mundo tenha melhorado nos tempos mais modernos, há momentos que temos que trabalhar com compiladores sem suporte à orientação a objetos.

 

Este artigo, portanto, se encaixa justamente nestas situações: tentar gerar alguma flexibilidade com abordagens simples de orientação a objetos em ambientes mais limitados.

 

 

Objeto - como pode ser definido

 

Em linguagens de mais alto nível (C++, por exemplo), um objeto pode ser alternativamente definido como um espaço de memória alocado para dados de natureza distintas. Este espaço de memória é referenciado como uma variável, portanto o objeto é chamado pelo seu nome.

 

Ou seja, um objeto pode conter dados de diferentes tipos e tamanhos. Desta forma, pode-se manipular vários dados acessando um bloco de memória específico, bem como altera-lo e clona-lo. Em uma analogia, é como uma ficha cadastral: há diversas informações de tamanhos e naturezas diferentes encapsuladas em um único "espaço físico" (papel), o qual pode ser manipulado e copiado. A cada dado destes dá-se o nome de parâmetro.

 

Entretanto, não há somente dados em um objeto. Há também funções. Logo, um objeto pode conter funções de software específicas dele. A cada função dessa, dá-se o nome de método.

 

Portanto, graficamente, um objeto é representado por:

 

Tabela 1 - Representação gráfica de um objeto

Espaço de memória do objeto

Nome
Parâmetros
Métodos

 

 

Em suma, o objeto forma um bloco especial de informações, capaz de carregar características próprias.

 

 

Implementação de um objeto em C

 

Conforme mostram as linguagens de mais alto nível, um objeto é originado a partir de uma classe, sendo que essa classe descreve tudo o que o objeto deve conter (é um "esqueleto" do objeto). Em C, uma classe pode ser descrita da seguinte maneira:

  • O objeto deve ser declarado como uma variável comum. Para isso ser válido, uma forma de implementação do objeto é este ser um tipo de variável criado a partir de tipos primitivos / já existentes. Portanto, uma classe de um objeto pode ser definida como um typedef de uma struct. Esta é a abordagem que será utilizada neste artigo.
  • Dentro desta struct, podem ser criadas variáveis diversas, de quaisquer tipos, conforme a necessidade. Estas variáveis constituem os parâmetros da classe (futuros parâmetros dos objetos).
  • Além dos parâmetros, os objetos podem conter métodos. Para tanto, utilizam-se ponteiros de função. Os ponteiros de função irão conter os endereços das funções a serem executadas (implementadas em lugares convenientes do código-fonte).

 

Uma classe, em termos de código, pode ser genericamente definida como:

 

 

E, consequentemente, um objeto é declarado como:

 

 

 

Inicialização do objeto

 

Assim como é preciso ser feito em quaisquer tipo de variável, todos os parâmetros e métodos (ponteiros de função) do objeto precisam ser inicializados (afinal, chamar um ponteiro de função que "aponta para o nada" é erro grave na certa). Aqui vem mais um conceito da orientação a objetos: dá-se o nome de método construtor a função que inicializa tudo em um objeto.

 

Portanto, o uso do método construtor não é só fundamental, mas sim vital ao funcionamento de objetos em C.

 

 

Exemplo de declaração e uso de um objeto em linguagem C

 

Abaixo, segue um exemplo de uso de um objeto feito em linguagem C. Tal exemplo consiste na definição da classe, declaração do objeto, popular seus parâmetros e chamar o único método que possui. O exemplo foi feito em um PC, mas a mesma ideia do código pode ser aproveitada por inteiro em qualquer sistema embarcado.

 

 

Assumindo que você utilize o GCC como compilador e que você salve este código como TesteObjetoC.c, compile-o com o seguinte comando:

 

 

E execute-o com o seguinte comando:

 

 

A execução irá ocorrer conforme mostra a Figura 1, mostrando que a mesma foi bem sucedida.

 

Output do programa
Figura 1 - Output do programa

 

 

Algumas operações com objetos 

 

O objeto aqui criado é bem simples, não possuindo implementações mais avançadas presentes em liguagens de mais alto nível. Ou seja, não suporta recursos avançados de orientação de objeto, porém funciona corretamente para operações básicas de orientação a objetos. Veja abaixo alguns exemplos de operações contempladas pelo objeto aqui desenvolvido:

 

a) Popular parâmetros do objeto

 

Uma vez declarado, o objeto pode ser populado simplesmente pela chamada de seu nome seguida de um ponto e o nome do parâmetro, exatamente como é feito nas linguagens de nível mais alto. Observe:

 

 

b) Chamadas de métodos

 

Analogamente, a chamada de métodos é feita pela chamada do nome do objeto seguida de um ponto e o nome do parâmetro, exatamente como é feito nas linguagens de nível mais alto. Observe:

 

 

c) Clonagem de objetos

 

A clonagem de objetos é definida como a cópia de todos os parâmetros e referências a métodos de um objeto-fonte para um objeto-destino. Na abordagem de objeto deste artigo, esta operação pode ser feita por um memcpy, por exemplo. Cabe aqui citar também que outra forma de clonar objetos é utilizar a cópia por referência.

 

d) Passagem de objetos como parâmetros

 

Uma das grandes vantagens de se utilizar objetos é poder passa-los como parâmetros de função, o que faz com que muitos dados possam ser passados por somente um parâmetro de função, tornando assim o código-fonte mais facilmente legível, sobretudo em funções com grandes manipulações de dados. 

 

Na abordagem do objeto aqui desenvolvido, isto também pode ser feito. Mas atenção: a passagem de objetos como parâmetros é muito mais eficiente e eficaz se feita como passagem de referência (ou seja, passa-se os ponteiros para os objetos). Observe:

 

 

 

Conclusão

 

Neste artigo, foi vista uma forma de se implementar um objeto em linguagem C, algo que pode ter utilidade em melhoria de arquitetura e código-fonte em microcontroladores e compiladores mais limitados (e antigos). Além da implementação destes objetos, foram dados exemplos de operações possíveis de serem realizadas com os mesmos, a fim de trazer o uso de objetos em C mais próximo do mundo real.

 

 

Referências

Sou engenheiro eletricista formado pela Faculdade de Engenharia de Guaratinguetá (FEG - UNESP) e trabalho com desenvolvimento de sistemas embarcados em São Paulo capital. Curioso e viciado em tecnologia, sempre busco me aprimorar na área de eletrônica e programação, em especial em desenvolvimento de firmware (área que mais gosto de trabalhar e estudar).Para mais informações, acesse minha página no Facebook:https://www.facebook.com/pbertoleti