<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-05-21T17:58:08+00:00</updated><id>/feed.xml</id><title type="html">Index of /</title><subtitle>Anotações do Vitalino Borges.</subtitle><author><name>Vitalino Borges</name></author><entry><title type="html">Emulando Orientação a Objetos em C</title><link href="/programacao/2023/06/27/poo-em-c/" rel="alternate" type="text/html" title="Emulando Orientação a Objetos em C" /><published>2023-06-27T00:00:00+00:00</published><updated>2023-06-27T00:00:00+00:00</updated><id>/programacao/2023/06/27/poo-em-c</id><content type="html" xml:base="/programacao/2023/06/27/poo-em-c/"><![CDATA[<p>A primeira vez que tomei conhecimento da existência da possibilidade de escrever em OO em C foi por meio dessa palestra:</p>

<p><img src="/assets/images/posts/programacao/oop-em-c/video-hisham.png" alt="Diagrama de herança" style="width: 60%;" /></p>

<p>Vale muito a pena estudar o <a href="https://hisham.hm/papers/talks/fisl16.pdf">slide</a> dele!</p>

<p>Fiquei muito empolgado com a ideia de poder entender orientação a objetos explorando recursos da linguagem C. Como sou um curioso dessa linguagem, deixo aqui neste artigo algumas anotações sobre esse tema.</p>

<h2 id="contextualizando">Contextualizando</h2>

<p>As várias linguagens de programação existentes podem ser classificadas de acordo com seus paradigmas. Podemos listar alguns dos paradigmas como:</p>

<ul>
  <li>Estruturado.</li>
  <li>Procedural.</li>
  <li>Orientado a Objetos.</li>
  <li>Orientado a Eventos.</li>
  <li>Funcional.</li>
  <li>Declarativo.</li>
  <li>Lógico.</li>
  <li>Paralela.</li>
</ul>

<p>Um paradigma irá determinar a visão que o programador terá do código, ou seja, determinará como o programador irá pensar o código de uma aplicação.</p>

<p>Muitas linguagens de programação são multi-paradigma, suportando nativamente um ou mais paradigmas. Como é o caso da linguagem C que suporta nativamente os paradigmas procedural e estruturado.</p>

<p>Um ponto interessante a se saber é que é possível emular um paradigma sobre uma linguagem que não a suporta nativamente. Por exemplo: é possível emular <a href="https://www.pluralsight.com/guides/functional-style-programming-using-c">programação funcional</a> ou <a href="https://ldeniau.web.cern.ch/ldeniau/">orientada a objetos</a> sobre a linguagem C.</p>

<p>É claro que essa emulação não terá a qualidade esperada de uma linguagem que a suporta nativamente. Então por que alguém se daria o trabalho de fazer uma gambiarra dessas? Vamos pontuar algumas possíveis justificativas:</p>

<ol>
  <li>
    <p>o programador pode apenas estar tentando se tornar mais íntimo de um paradigma específico, tentando <a href="https://staff.washington.edu/gmobus/Academics/TCES202/Moodle/OO-ProgrammingInC.html">entender</a> a sua implementação.</p>
  </li>
  <li>
    <p>um paradigma mais elaborado (como o OO) poderá ser emulado sobre uma linguagem mais simples por razões de performance (como por exemplo em sistemas embarcados usando C ao invés de C++).</p>
  </li>
  <li>
    <p>a reprodução de algumas características de um determinado paradigma sobre outra linguagem que não a suporta pode ser útil para tornar o código mais manutenível (algumas bibliotecas em C, por exemplo, se beneficiam de características de OO para tornar o código manutenível, <a href="https://dirk.rave.org/chap9.txt">neste outro caso</a> o autor utiliza OO em arquivos BAT do Windows, assim como outros exemplos, como OO em Shell Script).</p>
  </li>
</ol>

<h2 id="orientação-a-objetos-e-c">Orientação a Objetos e C</h2>

<p>Vamos discutir quais recursos da linguagem C podemos utilizar para emular a orientação a objetos. Existem alguns projetos open source que se beneficiam dessa emulação como design pattern:</p>

<ul>
  <li><a href="https://github.com/htop-dev/htop">htop</a>: visualizador de processos muito usado.</li>
  <li><a href="https://toshiocp.github.io/Gobject-tutorial/">GObject</a>: usada pela biblioteca GTK+, a base de ambientes gráficos GNOME, Cinnamon, MATE, XFCE, e LXDE.</li>
  <li><a href="https://lwn.net/Articles/444910/">Alguns padrões do kernel Linux</a>.</li>
</ul>

<blockquote>
  <p>Tem um livro onde o autor implementa alguns padrões de projeto da “Gangue dos 4” (originalmente pensados em C++) em C: <a href="https://leanpub.com/patternsinc">https://leanpub.com/patternsinc</a>.</p>
</blockquote>

<p>O paradigma de orientação a objetos se sustenta sobre três pilares:</p>

<ul>
  <li>Encapsulamento.</li>
  <li>Herança.</li>
  <li>Polimorfismo.</li>
</ul>

<p>Basicamente, a ideia é emular esses pilares usando recursos da linguagem C como:</p>

<ul>
  <li>structs opacas e ponteiros opacos como estruturas genéricas no código principal, e structs e ponteiros válidos somente no escopo de arquivo (válidos somente dentro de arquivos .c isolados do código principal) para emular encapsulamento de dados.</li>
  <li>structs aninhadas para emular herança.</li>
  <li>e ponteiros de função para emular polimorfismo.</li>
</ul>

<p>Então, em resumo, uma “classe” em C será um arquivo .c dedicado a declarar uma struct que aglutinará “atributos privados” (membros da struct acessíveis somente no escopo do arquivo), “métodos” (ponteiros para funções para acesso aos membros da struct), “método construtor” (função responsável por alocar memória na heap e popular alguns membros da struct), e outras funções e variáveis internas do “objeto”.</p>

<h2 id="garbage-collector-em-c">Garbage Collector em C</h2>

<p>No processo de compilação usaremos <code class="language-plaintext highlighter-rouge">-lgc</code>, no arquivo connection.c incluiremos o <code class="language-plaintext highlighter-rouge">gc.h</code>, e usaremos um malloc diferente chamado <code class="language-plaintext highlighter-rouge">GC_malloc()</code>.</p>

<p>A <a href="https://en.wikipedia.org/wiki/Boehm_garbage_collector">libgc</a> foi usada aqui para implementar um Garbage Collector (isso mesmo: garbage collector em C), com ela não será necessário usar <code class="language-plaintext highlighter-rouge">free()</code> para destruir nosso “objeto” instanciado.</p>

<blockquote>
  <p>Existem vários algoritmos diferentes de garbage collector (o Java, por exemplo, possui suporte a várias implementações de GC). A libgc (também chamada de Boehm-Demers-Weiser Garbage Collector) faz uso do tradicional <a href="https://www.hboehm.info/gc/index.html#details">Mark-and-Sweep</a>.</p>
</blockquote>

<h2 id="tá-bom-vamos-ver-como-fica">Tá bom, vamos ver como fica</h2>

<p>Para não ficar confuso, vamos ao seguinte código de exemplo de um cliente de rede. Mas antes duas coisas são importantes frisar:</p>

<ol>
  <li>o arquivo main.c não conhece o conteúdo do objeto connection (connection no escopo desse arquivo é uma struct opaca). Os acessos aos “métodos” do objeto ocorre através de artimética de ponteiros.</li>
  <li>todo o arquivo connection.c seria a implementação da “classe” (não só a struct). E observe que a struct connection possui membros vistos apenas no escopo deste arquivo. Desta forma, a “classe” Connection poderá ser modificada sem o conhecimento de quem a chama (abstração).</li>
</ol>

<h3 id="saída-da-execução">Saída da execução</h3>
<p><img src="/assets/images/posts/programacao/oop-em-c/output.png" alt="Compilação e execução do código." style="width: 60%;" /></p>

<h2 id="código">Código</h2>
<p>Compila com: <code class="language-plaintext highlighter-rouge">gcc main.c connection.c -o main -lgc</code></p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// main.c: Exemplo de C Orientado a Objeto</span>
<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
#include</span> <span class="cpf">"connection.h"</span><span class="cp">
</span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span> <span class="p">{</span>
 <span class="n">Connection</span> <span class="o">*</span><span class="n">connection</span><span class="p">;</span>
 <span class="n">Data</span> <span class="n">payload</span><span class="p">;</span>

 <span class="n">connection</span> <span class="o">=</span> <span class="n">new_Connection</span><span class="p">();</span> <span class="c1">// implementa uma espécie de "construtor"</span>
 <span class="n">payload</span> <span class="o">=</span> <span class="p">(</span><span class="n">Data</span><span class="p">)</span> <span class="s">"GET / HTTP/1.1"</span><span class="p">;</span>

 <span class="p">((</span><span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Connection</span> <span class="o">*</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="p">))</span> <span class="o">*</span><span class="p">((</span><span class="kt">long</span> <span class="kt">int</span> <span class="o">*</span><span class="p">)</span> <span class="n">connection</span><span class="o">+</span><span class="mi">0</span><span class="p">)</span> <span class="p">)</span> <span class="p">(</span><span class="n">connection</span><span class="p">,</span> <span class="s">"127.0.0.1"</span><span class="p">);</span> <span class="c1">// chama método setServer</span>
 <span class="p">((</span><span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Connection</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">))</span>    <span class="o">*</span><span class="p">((</span><span class="kt">long</span> <span class="kt">int</span> <span class="o">*</span><span class="p">)</span> <span class="n">connection</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span> <span class="p">)</span> <span class="p">(</span><span class="n">connection</span><span class="p">,</span> <span class="mi">80</span><span class="p">);</span>          <span class="c1">// chama método setPort</span>
 <span class="p">((</span><span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Connection</span> <span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">))</span>    <span class="o">*</span><span class="p">((</span><span class="kt">long</span> <span class="kt">int</span> <span class="o">*</span><span class="p">)</span> <span class="n">connection</span><span class="o">+</span><span class="mi">2</span><span class="p">)</span> <span class="p">)</span> <span class="p">(</span><span class="n">connection</span><span class="p">,</span> <span class="mi">6</span><span class="p">);</span>           <span class="c1">// chama método setProtocol</span>
 <span class="p">((</span><span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Connection</span> <span class="o">*</span><span class="p">,</span> <span class="n">Data</span><span class="p">))</span>   <span class="o">*</span><span class="p">((</span><span class="kt">long</span> <span class="kt">int</span> <span class="o">*</span><span class="p">)</span> <span class="n">connection</span><span class="o">+</span><span class="mi">3</span><span class="p">)</span> <span class="p">)</span> <span class="p">(</span><span class="n">connection</span><span class="p">,</span> <span class="n">payload</span><span class="p">);</span>     <span class="c1">// chama método setData</span>
 <span class="p">((</span><span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="p">)(</span><span class="n">Connection</span> <span class="o">*</span><span class="p">))</span>         <span class="o">*</span><span class="p">((</span><span class="kt">long</span> <span class="kt">int</span> <span class="o">*</span><span class="p">)</span> <span class="n">connection</span><span class="o">+</span><span class="mi">4</span><span class="p">)</span> <span class="p">)</span> <span class="p">(</span><span class="n">connection</span><span class="p">);</span>              <span class="c1">// chama método startConnection</span>

 <span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// connection.h: definição de dados abstratos</span>
<span class="cp">#ifndef CONNECTION_H__
#define CONNECTION_H__
</span>
<span class="cp">#define TCP 6
#define UDP 17
</span>
<span class="k">typedef</span> <span class="k">struct</span> <span class="n">_connection</span> <span class="n">Connection</span><span class="p">;</span>
<span class="k">typedef</span> <span class="kt">void</span><span class="o">*</span> <span class="n">Data</span><span class="p">;</span>
<span class="n">Connection</span><span class="o">*</span> <span class="nf">new_Connection</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>

<span class="cp">#endif
</span></code></pre></div></div>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// connection.c: Exemplo de implementação da "classe" connection</span>
<span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp">
#include</span> <span class="cpf">&lt;gc.h&gt;</span><span class="cp">
#include</span> <span class="cpf">"connection.h"</span><span class="cp">
</span>
<span class="k">typedef</span> <span class="nf">void</span> <span class="p">(</span><span class="o">*</span><span class="n">fpSetServer</span><span class="p">)(</span><span class="n">Connection</span><span class="o">*</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="p">);</span>
<span class="k">typedef</span> <span class="nf">void</span> <span class="p">(</span><span class="o">*</span><span class="n">fpSetPort</span><span class="p">)(</span><span class="n">Connection</span><span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">);</span>
<span class="k">typedef</span> <span class="nf">void</span> <span class="p">(</span><span class="o">*</span><span class="n">fpSetProtocol</span><span class="p">)(</span><span class="n">Connection</span><span class="o">*</span><span class="p">,</span> <span class="kt">int</span><span class="p">);</span>
<span class="k">typedef</span> <span class="nf">void</span> <span class="p">(</span><span class="o">*</span><span class="n">fpSetData</span><span class="p">)(</span><span class="n">Connection</span><span class="o">*</span><span class="p">,</span> <span class="n">Data</span> <span class="o">*</span><span class="p">);</span>
<span class="k">typedef</span> <span class="nf">void</span> <span class="p">(</span><span class="o">*</span><span class="n">fpStartConnection</span><span class="p">)(</span><span class="n">Connection</span><span class="o">*</span><span class="p">);</span>

<span class="k">struct</span> <span class="n">_connection</span> <span class="p">{</span>
 <span class="n">fpSetServer</span> <span class="n">setServer</span><span class="p">;</span>
 <span class="n">fpSetPort</span> <span class="n">setPort</span><span class="p">;</span>
 <span class="n">fpSetProtocol</span> <span class="n">setProtocol</span><span class="p">;</span>
 <span class="n">fpSetData</span> <span class="n">setData</span><span class="p">;</span>
 <span class="n">fpStartConnection</span> <span class="n">startConnection</span><span class="p">;</span>

 <span class="kt">char</span> <span class="o">*</span> <span class="n">serverIPv4</span><span class="p">;</span>
 <span class="kt">unsigned</span> <span class="kt">short</span> <span class="kt">int</span> <span class="n">serverPort</span><span class="p">;</span>
 <span class="kt">short</span> <span class="kt">int</span> <span class="n">serverProtocol</span><span class="p">;</span>
 <span class="n">Data</span> <span class="n">data</span><span class="p">;</span>
<span class="p">};</span>

<span class="kt">void</span> <span class="nf">setServer</span><span class="p">(</span><span class="n">Connection</span><span class="o">*</span> <span class="n">self</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">serverIPv4</span><span class="p">)</span> <span class="p">{</span>
 <span class="n">self</span><span class="o">-&gt;</span><span class="n">serverIPv4</span> <span class="o">=</span> <span class="n">serverIPv4</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">setPort</span><span class="p">(</span><span class="n">Connection</span><span class="o">*</span> <span class="n">self</span><span class="p">,</span> <span class="kt">int</span> <span class="n">serverPort</span><span class="p">)</span> <span class="p">{</span>
 <span class="n">self</span><span class="o">-&gt;</span><span class="n">serverPort</span> <span class="o">=</span> <span class="n">serverPort</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">setProtocol</span><span class="p">(</span><span class="n">Connection</span><span class="o">*</span> <span class="n">self</span><span class="p">,</span> <span class="kt">int</span> <span class="n">serverProtocol</span><span class="p">)</span> <span class="p">{</span>
 <span class="n">self</span><span class="o">-&gt;</span><span class="n">serverProtocol</span> <span class="o">=</span> <span class="n">serverProtocol</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">setData</span><span class="p">(</span><span class="n">Connection</span><span class="o">*</span> <span class="n">self</span><span class="p">,</span> <span class="n">Data</span> <span class="o">*</span><span class="n">data</span><span class="p">)</span> <span class="p">{</span>
 <span class="n">self</span><span class="o">-&gt;</span><span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="p">;</span>
<span class="p">}</span>

<span class="kt">void</span> <span class="nf">startConnection</span><span class="p">(</span><span class="n">Connection</span><span class="o">*</span> <span class="n">self</span><span class="p">)</span> <span class="p">{</span>
 <span class="n">printf</span><span class="p">(</span><span class="s">" Server: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">self</span><span class="o">-&gt;</span><span class="n">serverIPv4</span><span class="p">);</span>
 <span class="n">printf</span><span class="p">(</span><span class="s">" Port: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">self</span><span class="o">-&gt;</span><span class="n">serverPort</span><span class="p">);</span>
 <span class="n">printf</span><span class="p">(</span><span class="s">" Protocol: %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">self</span><span class="o">-&gt;</span><span class="n">serverProtocol</span> <span class="o">==</span> <span class="mi">6</span><span class="o">?</span> <span class="s">"TCP"</span> <span class="o">:</span> <span class="s">"UDP"</span><span class="p">);</span>
 <span class="n">printf</span><span class="p">(</span><span class="s">" Data: </span><span class="se">\"</span><span class="s">%s</span><span class="se">\"\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span> <span class="n">self</span><span class="o">-&gt;</span><span class="n">data</span><span class="p">);</span>
<span class="p">}</span>

<span class="n">Connection</span><span class="o">*</span> <span class="nf">new_Connection</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span> <span class="p">{</span>
 <span class="n">Connection</span> <span class="o">*</span><span class="n">obj</span><span class="p">;</span>
 <span class="n">obj</span> <span class="o">=</span> <span class="p">(</span><span class="n">Connection</span> <span class="o">*</span><span class="p">)</span> <span class="n">GC_malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">Connection</span><span class="p">));</span>

 <span class="n">obj</span><span class="o">-&gt;</span><span class="n">setServer</span>       <span class="o">=</span> <span class="n">setServer</span><span class="p">;</span>
 <span class="n">obj</span><span class="o">-&gt;</span><span class="n">setPort</span>         <span class="o">=</span> <span class="n">setPort</span><span class="p">;</span>
 <span class="n">obj</span><span class="o">-&gt;</span><span class="n">setProtocol</span>     <span class="o">=</span> <span class="n">setProtocol</span><span class="p">;</span>
 <span class="n">obj</span><span class="o">-&gt;</span><span class="n">setData</span>         <span class="o">=</span> <span class="n">setData</span><span class="p">;</span>
 <span class="n">obj</span><span class="o">-&gt;</span><span class="n">startConnection</span> <span class="o">=</span> <span class="n">startConnection</span><span class="p">;</span>

 <span class="k">return</span> <span class="n">obj</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="materiais-interessantes">Materiais interessantes</h2>

<p>Além da já citada palestra do Hisham Muhammad, alguns outros materiais interessantes sobre esse assunto:</p>

<ul>
  <li><a href="https://murilo.wordpress.com/2009/08/05/como-programar-em-c-orientado-a-objetos/">Como programar em C Orientado a Objetos</a></li>
  <li><a href="https://web.archive.org/web/20171009133835/http://codare.net/2009/08/04/c-escondendo-o-conteudo-de-structs-com-tipos-incompletos/">C Escondendo o conteúdo de structs com tipos incompletos</a></li>
  <li>Object-Oriented Techniques, Capítulo 8, livro <a href="http://www.sauleh.ir/fc98/static_files/materials/Richard%20Reese-Understanding%20and%20Using%20C%20Pointers-O%27Reilly%20Media%20(2013).pdf#%5B%7B%22num%22%3A662%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2Cnull%2C351.97696%2Cnull%5D">Understanding and Using C Pointers</a></li>
  <li><a href="https://libcello.org/learn/a-fat-pointer-library">A Fat Pointer Library</a></li>
</ul>]]></content><author><name>Vitalino Borges</name></author><category term="programacao" /><category term="c" /><category term="poo" /><summary type="html"><![CDATA[A primeira vez que tomei conhecimento da existência da possibilidade de escrever em OO em C foi por meio dessa palestra:]]></summary></entry></feed>