Click to add Text
Globalcode – Open4education
C/C++ – Modularização de Código C
Felipe de Andrade Neves Lavratti
Me. Eng.º Eletricista desenvolvedor de software
para Sistemas Embarcados
9 de agosto de 2014 – São Paulo – SP
Globalcode – Open4education
Experiência do
Apresentador
http://www.embarcados.com.br
9 ago 2014 2 / 44Modularização de Código C
Globalcode – Open4education
Principal bibliografia
Capítulo 11:
SOLID em C,
mas sem OOP;
Módulos mais complexos
e completos do que os
propostos;
9 ago 2014 3 / 44Modularização de Código C
Globalcode – Open4education
Agenda
Introdução
Porque modularizar
Exemplo
Quatro regras da modularização proposta
A composição do módulo
Usando o módulo “rectangle”
Demais tipos de módulos propostos
Módulo “vector”
Módulo “framebuffer”
Usando o módulo “vector” e “framebuffer”
9 ago 2014 4 / 44Modularização de Código C
Globalcode – Open4education
Modularizar é uma metodologia de
arquitetura de software.
O principal objetivo é manter o código
organizado, legível e desacoplado.
A modularização tem como sua principal
regra o SRP (Single Responsibility Principle)
e dependência em abstrações.
9 ago 2014 5 / 44Modularização de Código C
Globalcode – Open4education
Não é OOP porque não suporta herança
e polimorfismo facilmente.
Mas é OBP, programação
baseada em objetos.
9 ago 2014 6 / 44Modularização de Código C
Globalcode – Open4education
Porque modularizar
9 ago 2014 7 / 44Modularização de Código C
Globalcode – Open4education
Porque modularizar?
Por que permite a criação de excelentes
arquiteturas:
Design patterns* podem ser aplicados
Cria alicerces para boas práticas de programação:
Como, testes unitários, eliminação de código repetido,
abstração por interfaces, SOLID, incremento na
semântica, etc.
*variações ou simplificações de design patterns ou completos se
implementar OOP manualmente.
9 ago 2014 8 / 44Modularização de Código C
Globalcode – Open4education
Exemplo
A seguir função retirada da firmware de um produto real onde
a modularidade não foi empregada.
Depois um exemplo de como ficaria a mesma função se usada
a metodologia de modularização proposta.
9 ago 2014 9 / 44Modularização de Código C
Globalcode – Open4education
Exemplo: sem modularização.
Trecho de código
repetido ao longo da
firmware. Dependência em
implementação
Semântica obscura
9 ago 2014 10 / 44Modularização de Código C
Globalcode – Open4education
Exemplo: com modularização.
Dependência em
abstração
Semântica
incrementada
9 ago 2014 11 / 44Modularização de Código C
Globalcode – Open4education
Quatro regras da
modularização proposta
9 ago 2014 12 / 44Modularização de Código C
Globalcode – Open4education
Regras
Single Responsibility Princple (SRP)
Um módulo deve fazer uma coisa, e fazê-la bem.
Dependência em abstração
Código deve depender de uma funcionalidade, e não de
uma implementação.
Nomenclatura descritiva
Se um módulo e suas funções são bem nomeados, sua
funcionalidade fica clara.
Interface é documentação
Se todos os itens anteriores são obedecidos, então a
interface pode ser a única documentação necessária.
9 ago 2014 13 / 44Modularização de Código C
Globalcode – Open4education
A composição
do módulo
9 ago 2014 14 / 44Modularização de Código C
Globalcode – Open4education
INTERFACE
IMPLEMENTAÇÂO
DADOS
Composição do Módulo
Implementação (arquivo .c)
Implementação das
funções, definição dos
tipos privados,
comentários sobre a
implementação.
Dados (struct)
É o tipo do módulo,
quando existir, deve
ser sempre privado.
Contém todos os
dados relevantes,
como instâncias,
buffers, etc.
Interface (arquivo .h)
Funções de acesso,
definições de tipos e
comentários sobre a
abstração.
9 ago 2014 15 / 44Modularização de Código C
Globalcode – Open4education
Composição: Dados
Arquivo rectangle.c – projeto marsh – commit 7b4986a
https://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/rectangle.c
#include “rectangle.h”
...
struct s_rectangle_instance
{
color_t fill_color;
bool is_filled;
color_t border_color;
dim_t border_tickness;
bool has_border;
dim_t corner_radius;
...
};
...
O tipo é definido por uma struct,
seus membros são privados, não
podem ser acessados pelos
clientes diretamente.
todos os dados necessários para
a operação do módulo ficam
contidos nessa struct,
9 ago 2014 16 / 44Modularização de Código C
Globalcode – Open4education
Composição: Interface
#ifndef RECTANGLE_H_
#define RECTANGLE_H_
typedef struct s_rectangle_instance rectangle_t;
rectangle_t * rectangle_new(widget_t * parent);
void rectangle_delete(rectangle_t * const);
void rectangle_set_position(rectangle_t * const, dim_t x, dim_t y);
void rectangle_set_size(rectangle_t * const, dim_t width, dim_t height);
void rectangle_set_fill_color_html(rectangle_t * const, const char *
html_color_code);
void rectangle_set_border_tickness(rectangle_t * const, dim_t tickness);
void rectangle_set_border_color_html(rectangle_t * const, const char
*html_color_code);
void rectangle_set_rounded_corner_radius(rectangle_t * const, dim_t radius);
...
#endif /* RECTANGLE_H_ */
Arquivo rectangle.h – projeto marsh – commit 7b4986a
https://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/rectangle.h
Funções de criação e destruição.
Funções de funcionalidades.
Declaração do tipo,
9 ago 2014 17 / 44Modularização de Código C
Globalcode – Open4education
O módulo: Interface
#ifndef WIDGET_TREE_H_
#define WIDGET_TREE_H_
...
/* This method delete a widget, its creator, and all tree behind it,
* including the creator of each node.
* Ownership of obj and its children is transferred */
void widget_tree_delete(widget_t * obj);
...
#endif
Arquivo widget_tree.h – projeto marsh – commit 7b4986a
https://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/widget_tree.h
Na interface comentários relacionados a
abstração, como:
“o que faz” (não “como faz”);
o que é esperado dos parâmetros;
se a posse de algum tipo é transferida;
etc.
9 ago 2014 18 / 44Modularização de Código C
Globalcode – Open4education
Comp.: Implementação
Arquivo rectangle.c – projeto marsh – commit 7b4986a
https://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/rectangle.c
#include “rectangle.h”
...
rectangle_t * rectangle_new(widget_t * parent)
{
rectangle_t * obj = (rectangle_t *) calloc(1, sizeof(struct
s_rectangle_instance));
MEMORY_ALLOC_CHECK_RETURN(obj, NULL);
...
return obj;
}
void rectangle_delete(rectangle_t * const obj)
{
PTR_CHECK(obj, "rectangle");
my_log_delete(obj->log);
widget_delete_instance_only(obj->glyph);
free(obj);
}
...
Sem globais nem variáveis static,
para manter a reentrância.
Implementa as funcionalidades do
módulo.
rectangle_new e rectangle_delete
fazendo malloc para esconder dados
do rectangle_t do cliente;
9 ago 2014 19 / 44Modularização de Código C
Globalcode – Open4education
Usando o
módulo “rectangle”
9 ago 2014 20 / 44Modularização de Código C
Globalcode – Open4education
Usando o rectangle
rectangle_t * rect;
rect = rectangle_new(NULL); /* Alloc a new rectangle */
if (!rect) {
perror(“Unable to alocate a rectangle”);
}
/* Set rectangle positon to (10,10) */
rectangle_set_position(rect, 10, 10);
rectangle_delete(rect); /* delete the rectangle */
rect = NULL;
Exemplo de uso do módulo rectangle:
9 ago 2014 21 / 44Modularização de Código C
Globalcode – Open4education
#ifndef RECTANGLE_H_
#define RECTANGLE_H_
typedef struct s_rectangle_instance rectangle_t;
rectangle_t * rectangle_new(widget_t * parent);
void rectangle_delete(rectangle_t * const);
void rectangle_set_position(rectangle_t * const, dim_t x, dim_t y);
void rectangle_set_size(rectangle_t * const, dim_t width, dim_t height);
void rectangle_set_fill_color_html(rectangle_t * const, const char *
html_color_code);
void rectangle_set_border_tickness(rectangle_t * const, dim_t tickness);
void rectangle_set_border_color_html(rectangle_t * const, const char
*html_color_code);
void rectangle_set_rounded_corner_radius(rectangle_t * const, dim_t radius);
...
#endif /* RECTANGLE_H_ */
Usando o rectangle
Arquivo rectangle.h – projeto marsh – commit 7b4986a
https://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/rectangle.h
forward declaration
9 ago 2014 22 / 44Modularização de Código C
Globalcode – Open4education
Usando o rectangle
rectangle_t * rec = rectangle_new(NULL);
rec->has_border;
Acessando os membros internos de rectangle diretamente não compila:
rectangle_t rect;
Porém usar rectangle_t na stack também não compila:
error: forward declaration of ‘rectangle_t {aka struct s_rectangle_instance}’
error: aggregate ‘rectangle_t rect’ has incomplete type and cannot be defined
Como rectangle_t é uma forward declaration, os membros internos da struct do módulo são
invisíveis ao código do cliente.
9 ago 2014 23 / 44Modularização de Código C
Globalcode – Open4education
Demais tipos de
módulos propostos
9 ago 2014 24 / 44Modularização de Código C
Globalcode – Open4education
Tipos de módulos
Quanto a instância:
de instância única;
ou multiplamente instanciável.
Quanto ao local da instância:
no heap somente;
ou no heap ou stack.
Quanto à implementação variável:
de implementação fixa;
ou selecionável na compilação;
rectangle
vector
framebuffer
9 ago 2014 25 / 44Modularização de Código C
Globalcode – Open4education
Módulo vector
(instância na stack)
9 ago 2014 26 / 44Modularização de Código C
Globalcode – Open4education
Instância na stack
A struct privada do módulo precisa ser visível ao
código do cliente.
Pode ter seus membros internos acessados
sem erro no compilador.
Informe ao cliente que aqueles dados são
privados:
Usando um header com nome “_private.h”
Nomeando a struct com “_private”
Acrescentando comentário na struct
E até colocando “__” nos nomes dos
membros da struct privada.
9 ago 2014 27 / 44Modularização de Código C
Globalcode – Open4education
Interface do vector
Arquivo vector.h – projeto chelper – commit 4273eed
http://github.com/felipe-lavratti/chelper/blob/4273eedd76d8fb6dc22dd978abad5ab7636bf39b/include/chelper/vector.h
#ifndef VECTOR_H_
#define VECTOR_H_
#include "private_helper_types.h“
...
typedef struct s_vector_private vector_t;
void vector_init(vector_t *, size_t item_size);
void vector_deinit(vector_t *);
size_t vector_size(vector_t *);
BUFFER_PTR vector_at(vector_t *, size_t pos);
void vector_add(vector_t *, BUFFER_PTR_RDOLY item);
void vector_remove(vector_t *, size_t pos);
void vector_clear(vector_t *);
...
#endif /* VECTOR_H_ */
Indicação de dados
privados no nome
Não é forward declaration
Não fazem malloc/free
Usam vector_t alocado
pelo cliente
9 ago 2014 28 / 44Modularização de Código C
Globalcode – Open4education
Dados privados
Arquivo private_helper_types.h – projeto chelper – commit 4273eed
http://github.com/felipe-lavratti/chelper/blob/4273eedd76d8fb6dc22dd978abad5ab7636bf39b/include/chelper/private_helper_types.h
#ifndef PRIVATE_HELPER_TYPES_H_
#define PRIVATE_HELPER_TYPES_H_
/*
* All types defined in this header should never be directly derreferenced nor
* have its member accessed by external code. These are private data belonging to
* internal modules only.
*
* Each of these structs has a non forward typedef meant to be allocated by client
* code and used only through chelper's public functions.
*/
struct s_vector_private
{
/* This data is private, do not touch it */
size_t __item_size;
uint32_t __used_slots;
uint32_t __buffer_total_slots;
uint8_t * __buffer;
};
...
#endif /* PRIVATE_HELPER_TYPES_H_ */
9 ago 2014 29 / 44Modularização de Código C
Globalcode – Open4education
Implementação do vector
Arquivo vector.c – projeto chelper – commit 4273eed
http://github.com/felipe-lavratti/chelper/blob/4273eedd76d8fb6dc22dd978abad5ab7636bf39b/lib/vector.c
#include “chelper/vector.h”
...
void vector_init(vector_t * cobj, size_t item_size)
{
struct s_vector_private * obj = (struct s_vector_private *)cobj;
PTR_CHECK(obj, "vector");
obj->__item_size = item_size;
obj->__buffer = (uint8_t *)calloc(2, obj->__item_size);
MEMORY_ALLOC_CHECK(obj->__buffer);
obj->__buffer_total_slots = 2;
obj->__used_slots = 0;
}
void vector_deinit(vector_t *cobj)
{
struct s_vector_private * obj = (struct s_vector_private *)cobj;
PTR_CHECK(obj, "vector");
if (obj->__buffer) {
free(obj->__buffer);
obj->__buffer = NULL;
}
}
9 ago 2014 30 / 44Modularização de Código C
Globalcode – Open4education
Módulo framebuffer
(instância única e
implementação selecionável)
9 ago 2014 31 / 44Modularização de Código C
Globalcode – Open4education
Instância única
Tipo não é alocável pelo cliente.
É interno e static.
Não é reentrante.
9 ago 2014 32 / 44Modularização de Código C
Globalcode – Open4education
Interface do framebuffer
Arquivo framebuffer.h – projeto marsh – commit 7b4986a
http://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/framebuffer.h
#ifndef FRAMEBUFFER_H_
#define FRAMEBUFFER_H_
…
void framebuffer_init(void);
void framebuffer_deinit(void);
pixel_t *framebuffer_start(void);
pixel_t *framebuffer_at(pixel_t x, pixel_t y);
size_t framebuffer_width(void);
size_t framebuffer_height(void);
const area_t * framebuffer_area(void);
void framebuffer_inform_written_area(size_t x,
size_t y, size_t width, size_t height);
#endif /* FRAMEBUFFER_H_ */
Não tem parâmetro de
instância.
9 ago 2014 33 / 44Modularização de Código C
Globalcode – Open4education
Interface do framebuffer
Arquivo framebuffer.c – projeto marsh – commit 7b4986a
http://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/platform_src/test_mocks/framebuffer.c
#include "framebuffer.h“
#include "area.h“
...
static pixel_t* pFb;
...
void framebuffer_init()
{
if (!_fb_not_initd())
free(pFb);
pFb = (pixel_t *)calloc(FRAMEBUFFER_HEIGHT * FRAMEBUFFER_WIDTH, sizeof(pixel_t));
}
void framebuffer_delete()
{
if (_fb_not_initd())
return;
if (pFb)
free(pFb);
pFb = NULL;
}
...
Dados privados, nesse caso é só um apontador.
Módulo independente de plataforma pode ser
usado em código dependente de plataforma.
9 ago 2014 34 / 44Modularização de Código C
Globalcode – Open4education
Implementação selecionável
A implementação é escolhida na compilação, pelo
Makefile.
Todas implementam a mesma interface
Apenas uma interface de acesso ao módulo
Diversas implementações são possíveis.
Comumente usado para organizar código multi-
plataforma sem #ifdefs.
9 ago 2014 35 / 44Modularização de Código C
Globalcode – Open4education
Organização de pastas para
código multi-plataforma
Código dependente de plataforma
Código independente de plataforma
9 ago 2014 36 / 44Modularização de Código C
Globalcode – Open4education
Organização de pastas
Arquivos de implementação
são escolhidos de acordo
com o target do Makefile
Nome ruim, não passa a
funcionalidade para o
cliente, thread não diz
respeito à abstração, e sim
à implementação.
Para o código cliente do framebuffer, não
pode haver diferença de uso se compilado
para test_mocks ou linux_simulator.
9 ago 2014 37 / 44Modularização de Código C
Globalcode – Open4education
Usando o
módulo vector
e framebuffer
9 ago 2014 38 / 44Modularização de Código C
Globalcode – Open4education
Usando o vector
#include <chelper/vector.h>
vector_t * vect_heap = malloc(sizeof(*vect_heap));
vector_t vect_stack;
vector_init(vect_heap, ...);
vector_init(&vect_stack, ...);
vect_heap->__item_size = 3;
vect_heap.__item_size = 3;
...
vector_deinit(vect_heap);
free(vect_heap);
vect_heap = NULL;
vector_deinit(&vect_heap);
Exemplo de uso do módulo vector, alocando no heap e na stack:
Mesmo esses acessos sendo considerados
ilegais, esse código compila.
9 ago 2014 39 / 44Modularização de Código C
Globalcode – Open4education
Usando o framebuffer
#include “framebuffer.h”
framebuffer_init();
...
pixel_t * fb_point = framebuffer_at(100, 20);
...
framebuffer_deinit();
Exemplo de uso do módulo framebuffer:
9 ago 2014 40 / 44Modularização de Código C
Globalcode – Open4education
Referências
9 ago 2014 41 / 44Modularização de Código C
Globalcode – Open4education
Test-Driven Development for Embedded C
James W. Grenning
Para um excelente conteúdo sobre unit-testing e arquitetura modularizada.
A leitura do capítulo 11 “SOLID, Flexible, and Testable Designs” é
altamente recomendada.
Design Patterns for Embedded Systems in C
Bruce Powel Douglass
Como excelente referência de patterns em C para o emprego prático da
modularidade.
Referências
9 ago 2014 42 / 44Modularização de Código C
Globalcode – Open4education
Projeto Marsh e Projeto Chelper
Ambos são exemplos das técnicas de modularidade apresentadas.
http://github.com/felipe-lavratti
Chelper é uma biblioteca de extensão da
linguagem C, com código frequentemente utilizado
(vector, linked list, signal/slot, etc.)
Marsh é uma interface gráfica auto contida,
independente de OS e escrito em C, para rodar
tanto em firmware baremetal quanto sobre
sistemas operacionais.
CONTRIBUIDORES SÃO BEM VINDOS!
Referências
9 ago 2014 43 / 44Modularização de Código C
Globalcode – Open4education
Muito obrigado!
Dúvidas?
felipelav no gmail
9 ago 2014 44 / 44Modularização de Código C

TDC2014 SP - C/C++ - Modularização de Código C

  • 1.
    Click to addText Globalcode – Open4education C/C++ – Modularização de Código C Felipe de Andrade Neves Lavratti Me. Eng.º Eletricista desenvolvedor de software para Sistemas Embarcados 9 de agosto de 2014 – São Paulo – SP
  • 2.
    Globalcode – Open4education Experiênciado Apresentador http://www.embarcados.com.br 9 ago 2014 2 / 44Modularização de Código C
  • 3.
    Globalcode – Open4education Principalbibliografia Capítulo 11: SOLID em C, mas sem OOP; Módulos mais complexos e completos do que os propostos; 9 ago 2014 3 / 44Modularização de Código C
  • 4.
    Globalcode – Open4education Agenda Introdução Porquemodularizar Exemplo Quatro regras da modularização proposta A composição do módulo Usando o módulo “rectangle” Demais tipos de módulos propostos Módulo “vector” Módulo “framebuffer” Usando o módulo “vector” e “framebuffer” 9 ago 2014 4 / 44Modularização de Código C
  • 5.
    Globalcode – Open4education Modularizaré uma metodologia de arquitetura de software. O principal objetivo é manter o código organizado, legível e desacoplado. A modularização tem como sua principal regra o SRP (Single Responsibility Principle) e dependência em abstrações. 9 ago 2014 5 / 44Modularização de Código C
  • 6.
    Globalcode – Open4education Nãoé OOP porque não suporta herança e polimorfismo facilmente. Mas é OBP, programação baseada em objetos. 9 ago 2014 6 / 44Modularização de Código C
  • 7.
    Globalcode – Open4education Porquemodularizar 9 ago 2014 7 / 44Modularização de Código C
  • 8.
    Globalcode – Open4education Porquemodularizar? Por que permite a criação de excelentes arquiteturas: Design patterns* podem ser aplicados Cria alicerces para boas práticas de programação: Como, testes unitários, eliminação de código repetido, abstração por interfaces, SOLID, incremento na semântica, etc. *variações ou simplificações de design patterns ou completos se implementar OOP manualmente. 9 ago 2014 8 / 44Modularização de Código C
  • 9.
    Globalcode – Open4education Exemplo Aseguir função retirada da firmware de um produto real onde a modularidade não foi empregada. Depois um exemplo de como ficaria a mesma função se usada a metodologia de modularização proposta. 9 ago 2014 9 / 44Modularização de Código C
  • 10.
    Globalcode – Open4education Exemplo:sem modularização. Trecho de código repetido ao longo da firmware. Dependência em implementação Semântica obscura 9 ago 2014 10 / 44Modularização de Código C
  • 11.
    Globalcode – Open4education Exemplo:com modularização. Dependência em abstração Semântica incrementada 9 ago 2014 11 / 44Modularização de Código C
  • 12.
    Globalcode – Open4education Quatroregras da modularização proposta 9 ago 2014 12 / 44Modularização de Código C
  • 13.
    Globalcode – Open4education Regras SingleResponsibility Princple (SRP) Um módulo deve fazer uma coisa, e fazê-la bem. Dependência em abstração Código deve depender de uma funcionalidade, e não de uma implementação. Nomenclatura descritiva Se um módulo e suas funções são bem nomeados, sua funcionalidade fica clara. Interface é documentação Se todos os itens anteriores são obedecidos, então a interface pode ser a única documentação necessária. 9 ago 2014 13 / 44Modularização de Código C
  • 14.
    Globalcode – Open4education Acomposição do módulo 9 ago 2014 14 / 44Modularização de Código C
  • 15.
    Globalcode – Open4education INTERFACE IMPLEMENTAÇÂO DADOS Composiçãodo Módulo Implementação (arquivo .c) Implementação das funções, definição dos tipos privados, comentários sobre a implementação. Dados (struct) É o tipo do módulo, quando existir, deve ser sempre privado. Contém todos os dados relevantes, como instâncias, buffers, etc. Interface (arquivo .h) Funções de acesso, definições de tipos e comentários sobre a abstração. 9 ago 2014 15 / 44Modularização de Código C
  • 16.
    Globalcode – Open4education Composição:Dados Arquivo rectangle.c – projeto marsh – commit 7b4986a https://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/rectangle.c #include “rectangle.h” ... struct s_rectangle_instance { color_t fill_color; bool is_filled; color_t border_color; dim_t border_tickness; bool has_border; dim_t corner_radius; ... }; ... O tipo é definido por uma struct, seus membros são privados, não podem ser acessados pelos clientes diretamente. todos os dados necessários para a operação do módulo ficam contidos nessa struct, 9 ago 2014 16 / 44Modularização de Código C
  • 17.
    Globalcode – Open4education Composição:Interface #ifndef RECTANGLE_H_ #define RECTANGLE_H_ typedef struct s_rectangle_instance rectangle_t; rectangle_t * rectangle_new(widget_t * parent); void rectangle_delete(rectangle_t * const); void rectangle_set_position(rectangle_t * const, dim_t x, dim_t y); void rectangle_set_size(rectangle_t * const, dim_t width, dim_t height); void rectangle_set_fill_color_html(rectangle_t * const, const char * html_color_code); void rectangle_set_border_tickness(rectangle_t * const, dim_t tickness); void rectangle_set_border_color_html(rectangle_t * const, const char *html_color_code); void rectangle_set_rounded_corner_radius(rectangle_t * const, dim_t radius); ... #endif /* RECTANGLE_H_ */ Arquivo rectangle.h – projeto marsh – commit 7b4986a https://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/rectangle.h Funções de criação e destruição. Funções de funcionalidades. Declaração do tipo, 9 ago 2014 17 / 44Modularização de Código C
  • 18.
    Globalcode – Open4education Omódulo: Interface #ifndef WIDGET_TREE_H_ #define WIDGET_TREE_H_ ... /* This method delete a widget, its creator, and all tree behind it, * including the creator of each node. * Ownership of obj and its children is transferred */ void widget_tree_delete(widget_t * obj); ... #endif Arquivo widget_tree.h – projeto marsh – commit 7b4986a https://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/widget_tree.h Na interface comentários relacionados a abstração, como: “o que faz” (não “como faz”); o que é esperado dos parâmetros; se a posse de algum tipo é transferida; etc. 9 ago 2014 18 / 44Modularização de Código C
  • 19.
    Globalcode – Open4education Comp.:Implementação Arquivo rectangle.c – projeto marsh – commit 7b4986a https://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/rectangle.c #include “rectangle.h” ... rectangle_t * rectangle_new(widget_t * parent) { rectangle_t * obj = (rectangle_t *) calloc(1, sizeof(struct s_rectangle_instance)); MEMORY_ALLOC_CHECK_RETURN(obj, NULL); ... return obj; } void rectangle_delete(rectangle_t * const obj) { PTR_CHECK(obj, "rectangle"); my_log_delete(obj->log); widget_delete_instance_only(obj->glyph); free(obj); } ... Sem globais nem variáveis static, para manter a reentrância. Implementa as funcionalidades do módulo. rectangle_new e rectangle_delete fazendo malloc para esconder dados do rectangle_t do cliente; 9 ago 2014 19 / 44Modularização de Código C
  • 20.
    Globalcode – Open4education Usandoo módulo “rectangle” 9 ago 2014 20 / 44Modularização de Código C
  • 21.
    Globalcode – Open4education Usandoo rectangle rectangle_t * rect; rect = rectangle_new(NULL); /* Alloc a new rectangle */ if (!rect) { perror(“Unable to alocate a rectangle”); } /* Set rectangle positon to (10,10) */ rectangle_set_position(rect, 10, 10); rectangle_delete(rect); /* delete the rectangle */ rect = NULL; Exemplo de uso do módulo rectangle: 9 ago 2014 21 / 44Modularização de Código C
  • 22.
    Globalcode – Open4education #ifndefRECTANGLE_H_ #define RECTANGLE_H_ typedef struct s_rectangle_instance rectangle_t; rectangle_t * rectangle_new(widget_t * parent); void rectangle_delete(rectangle_t * const); void rectangle_set_position(rectangle_t * const, dim_t x, dim_t y); void rectangle_set_size(rectangle_t * const, dim_t width, dim_t height); void rectangle_set_fill_color_html(rectangle_t * const, const char * html_color_code); void rectangle_set_border_tickness(rectangle_t * const, dim_t tickness); void rectangle_set_border_color_html(rectangle_t * const, const char *html_color_code); void rectangle_set_rounded_corner_radius(rectangle_t * const, dim_t radius); ... #endif /* RECTANGLE_H_ */ Usando o rectangle Arquivo rectangle.h – projeto marsh – commit 7b4986a https://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/rectangle.h forward declaration 9 ago 2014 22 / 44Modularização de Código C
  • 23.
    Globalcode – Open4education Usandoo rectangle rectangle_t * rec = rectangle_new(NULL); rec->has_border; Acessando os membros internos de rectangle diretamente não compila: rectangle_t rect; Porém usar rectangle_t na stack também não compila: error: forward declaration of ‘rectangle_t {aka struct s_rectangle_instance}’ error: aggregate ‘rectangle_t rect’ has incomplete type and cannot be defined Como rectangle_t é uma forward declaration, os membros internos da struct do módulo são invisíveis ao código do cliente. 9 ago 2014 23 / 44Modularização de Código C
  • 24.
    Globalcode – Open4education Demaistipos de módulos propostos 9 ago 2014 24 / 44Modularização de Código C
  • 25.
    Globalcode – Open4education Tiposde módulos Quanto a instância: de instância única; ou multiplamente instanciável. Quanto ao local da instância: no heap somente; ou no heap ou stack. Quanto à implementação variável: de implementação fixa; ou selecionável na compilação; rectangle vector framebuffer 9 ago 2014 25 / 44Modularização de Código C
  • 26.
    Globalcode – Open4education Módulovector (instância na stack) 9 ago 2014 26 / 44Modularização de Código C
  • 27.
    Globalcode – Open4education Instânciana stack A struct privada do módulo precisa ser visível ao código do cliente. Pode ter seus membros internos acessados sem erro no compilador. Informe ao cliente que aqueles dados são privados: Usando um header com nome “_private.h” Nomeando a struct com “_private” Acrescentando comentário na struct E até colocando “__” nos nomes dos membros da struct privada. 9 ago 2014 27 / 44Modularização de Código C
  • 28.
    Globalcode – Open4education Interfacedo vector Arquivo vector.h – projeto chelper – commit 4273eed http://github.com/felipe-lavratti/chelper/blob/4273eedd76d8fb6dc22dd978abad5ab7636bf39b/include/chelper/vector.h #ifndef VECTOR_H_ #define VECTOR_H_ #include "private_helper_types.h“ ... typedef struct s_vector_private vector_t; void vector_init(vector_t *, size_t item_size); void vector_deinit(vector_t *); size_t vector_size(vector_t *); BUFFER_PTR vector_at(vector_t *, size_t pos); void vector_add(vector_t *, BUFFER_PTR_RDOLY item); void vector_remove(vector_t *, size_t pos); void vector_clear(vector_t *); ... #endif /* VECTOR_H_ */ Indicação de dados privados no nome Não é forward declaration Não fazem malloc/free Usam vector_t alocado pelo cliente 9 ago 2014 28 / 44Modularização de Código C
  • 29.
    Globalcode – Open4education Dadosprivados Arquivo private_helper_types.h – projeto chelper – commit 4273eed http://github.com/felipe-lavratti/chelper/blob/4273eedd76d8fb6dc22dd978abad5ab7636bf39b/include/chelper/private_helper_types.h #ifndef PRIVATE_HELPER_TYPES_H_ #define PRIVATE_HELPER_TYPES_H_ /* * All types defined in this header should never be directly derreferenced nor * have its member accessed by external code. These are private data belonging to * internal modules only. * * Each of these structs has a non forward typedef meant to be allocated by client * code and used only through chelper's public functions. */ struct s_vector_private { /* This data is private, do not touch it */ size_t __item_size; uint32_t __used_slots; uint32_t __buffer_total_slots; uint8_t * __buffer; }; ... #endif /* PRIVATE_HELPER_TYPES_H_ */ 9 ago 2014 29 / 44Modularização de Código C
  • 30.
    Globalcode – Open4education Implementaçãodo vector Arquivo vector.c – projeto chelper – commit 4273eed http://github.com/felipe-lavratti/chelper/blob/4273eedd76d8fb6dc22dd978abad5ab7636bf39b/lib/vector.c #include “chelper/vector.h” ... void vector_init(vector_t * cobj, size_t item_size) { struct s_vector_private * obj = (struct s_vector_private *)cobj; PTR_CHECK(obj, "vector"); obj->__item_size = item_size; obj->__buffer = (uint8_t *)calloc(2, obj->__item_size); MEMORY_ALLOC_CHECK(obj->__buffer); obj->__buffer_total_slots = 2; obj->__used_slots = 0; } void vector_deinit(vector_t *cobj) { struct s_vector_private * obj = (struct s_vector_private *)cobj; PTR_CHECK(obj, "vector"); if (obj->__buffer) { free(obj->__buffer); obj->__buffer = NULL; } } 9 ago 2014 30 / 44Modularização de Código C
  • 31.
    Globalcode – Open4education Móduloframebuffer (instância única e implementação selecionável) 9 ago 2014 31 / 44Modularização de Código C
  • 32.
    Globalcode – Open4education Instânciaúnica Tipo não é alocável pelo cliente. É interno e static. Não é reentrante. 9 ago 2014 32 / 44Modularização de Código C
  • 33.
    Globalcode – Open4education Interfacedo framebuffer Arquivo framebuffer.h – projeto marsh – commit 7b4986a http://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/src/framebuffer.h #ifndef FRAMEBUFFER_H_ #define FRAMEBUFFER_H_ … void framebuffer_init(void); void framebuffer_deinit(void); pixel_t *framebuffer_start(void); pixel_t *framebuffer_at(pixel_t x, pixel_t y); size_t framebuffer_width(void); size_t framebuffer_height(void); const area_t * framebuffer_area(void); void framebuffer_inform_written_area(size_t x, size_t y, size_t width, size_t height); #endif /* FRAMEBUFFER_H_ */ Não tem parâmetro de instância. 9 ago 2014 33 / 44Modularização de Código C
  • 34.
    Globalcode – Open4education Interfacedo framebuffer Arquivo framebuffer.c – projeto marsh – commit 7b4986a http://github.com/felipe-lavratti/marsh/blob/7b4986ad0a9968d6ce140f8f46b4ac8cb16d4013/marsh/platform_src/test_mocks/framebuffer.c #include "framebuffer.h“ #include "area.h“ ... static pixel_t* pFb; ... void framebuffer_init() { if (!_fb_not_initd()) free(pFb); pFb = (pixel_t *)calloc(FRAMEBUFFER_HEIGHT * FRAMEBUFFER_WIDTH, sizeof(pixel_t)); } void framebuffer_delete() { if (_fb_not_initd()) return; if (pFb) free(pFb); pFb = NULL; } ... Dados privados, nesse caso é só um apontador. Módulo independente de plataforma pode ser usado em código dependente de plataforma. 9 ago 2014 34 / 44Modularização de Código C
  • 35.
    Globalcode – Open4education Implementaçãoselecionável A implementação é escolhida na compilação, pelo Makefile. Todas implementam a mesma interface Apenas uma interface de acesso ao módulo Diversas implementações são possíveis. Comumente usado para organizar código multi- plataforma sem #ifdefs. 9 ago 2014 35 / 44Modularização de Código C
  • 36.
    Globalcode – Open4education Organizaçãode pastas para código multi-plataforma Código dependente de plataforma Código independente de plataforma 9 ago 2014 36 / 44Modularização de Código C
  • 37.
    Globalcode – Open4education Organizaçãode pastas Arquivos de implementação são escolhidos de acordo com o target do Makefile Nome ruim, não passa a funcionalidade para o cliente, thread não diz respeito à abstração, e sim à implementação. Para o código cliente do framebuffer, não pode haver diferença de uso se compilado para test_mocks ou linux_simulator. 9 ago 2014 37 / 44Modularização de Código C
  • 38.
    Globalcode – Open4education Usandoo módulo vector e framebuffer 9 ago 2014 38 / 44Modularização de Código C
  • 39.
    Globalcode – Open4education Usandoo vector #include <chelper/vector.h> vector_t * vect_heap = malloc(sizeof(*vect_heap)); vector_t vect_stack; vector_init(vect_heap, ...); vector_init(&vect_stack, ...); vect_heap->__item_size = 3; vect_heap.__item_size = 3; ... vector_deinit(vect_heap); free(vect_heap); vect_heap = NULL; vector_deinit(&vect_heap); Exemplo de uso do módulo vector, alocando no heap e na stack: Mesmo esses acessos sendo considerados ilegais, esse código compila. 9 ago 2014 39 / 44Modularização de Código C
  • 40.
    Globalcode – Open4education Usandoo framebuffer #include “framebuffer.h” framebuffer_init(); ... pixel_t * fb_point = framebuffer_at(100, 20); ... framebuffer_deinit(); Exemplo de uso do módulo framebuffer: 9 ago 2014 40 / 44Modularização de Código C
  • 41.
    Globalcode – Open4education Referências 9ago 2014 41 / 44Modularização de Código C
  • 42.
    Globalcode – Open4education Test-DrivenDevelopment for Embedded C James W. Grenning Para um excelente conteúdo sobre unit-testing e arquitetura modularizada. A leitura do capítulo 11 “SOLID, Flexible, and Testable Designs” é altamente recomendada. Design Patterns for Embedded Systems in C Bruce Powel Douglass Como excelente referência de patterns em C para o emprego prático da modularidade. Referências 9 ago 2014 42 / 44Modularização de Código C
  • 43.
    Globalcode – Open4education ProjetoMarsh e Projeto Chelper Ambos são exemplos das técnicas de modularidade apresentadas. http://github.com/felipe-lavratti Chelper é uma biblioteca de extensão da linguagem C, com código frequentemente utilizado (vector, linked list, signal/slot, etc.) Marsh é uma interface gráfica auto contida, independente de OS e escrito em C, para rodar tanto em firmware baremetal quanto sobre sistemas operacionais. CONTRIBUIDORES SÃO BEM VINDOS! Referências 9 ago 2014 43 / 44Modularização de Código C
  • 44.
    Globalcode – Open4education Muitoobrigado! Dúvidas? felipelav no gmail 9 ago 2014 44 / 44Modularização de Código C