O slideshow foi denunciado.
Click to add Text
Globalcode – Open4education
C/C++ – Modularização de Código C
Felipe de Andrade Neves Lavratti
Me. Eng.º...
Globalcode – Open4education
Experiência do
Apresentador
http://www.embarcados.com.br
9 ago 2014 2 / 44Modularização de Cód...
Globalcode – Open4education
Principal bibliografia
Capítulo 11:
SOLID em C,
mas sem OOP;
Módulos mais complexos
e completo...
Globalcode – Open4education
Agenda
Introdução
Porque modularizar
Exemplo
Quatro regras da modularização proposta
A composi...
Globalcode – Open4education
Modularizar é uma metodologia de
arquitetura de software.
O principal objetivo é manter o códi...
Globalcode – Open4education
Não é OOP porque não suporta herança
e polimorfismo facilmente.
Mas é OBP, programação
baseada...
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* pod...
Globalcode – Open4education
Exemplo
A seguir função retirada da firmware de um produto real onde
a modularidade não foi em...
Globalcode – Open4education
Exemplo: sem modularização.
Trecho de código
repetido ao longo da
firmware. Dependência em
imp...
Globalcode – Open4education
Exemplo: com modularização.
Dependência em
abstração
Semântica
incrementada
9 ago 2014 11 / 44...
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.
Dep...
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 da...
Globalcode – Open4education
Composição: Dados
Arquivo rectangle.c – projeto marsh – commit 7b4986a
https://github.com/feli...
Globalcode – Open4education
Composição: Interface
#ifndef RECTANGLE_H_
#define RECTANGLE_H_
typedef struct s_rectangle_ins...
Globalcode – Open4education
O módulo: Interface
#ifndef WIDGET_TREE_H_
#define WIDGET_TREE_H_
...
/* This method delete a ...
Globalcode – Open4education
Comp.: Implementação
Arquivo rectangle.c – projeto marsh – commit 7b4986a
https://github.com/f...
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 */...
Globalcode – Open4education
#ifndef RECTANGLE_H_
#define RECTANGLE_H_
typedef struct s_rectangle_instance rectangle_t;
rec...
Globalcode – Open4education
Usando o rectangle
rectangle_t * rec = rectangle_new(NULL);
rec->has_border;
Acessando os memb...
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...
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 t...
Globalcode – Open4education
Interface do vector
Arquivo vector.h – projeto chelper – commit 4273eed
http://github.com/feli...
Globalcode – Open4education
Dados privados
Arquivo private_helper_types.h – projeto chelper – commit 4273eed
http://github...
Globalcode – Open4education
Implementação do vector
Arquivo vector.c – projeto chelper – commit 4273eed
http://github.com/...
Globalcode – Open4education
Módulo framebuffer
(instância única e
implementação selecionável)
9 ago 2014 31 / 44Modulariza...
Globalcode – Open4education
Instância única
Tipo não é alocável pelo cliente.
É interno e static.
Não é reentrante.
9 ago ...
Globalcode – Open4education
Interface do framebuffer
Arquivo framebuffer.h – projeto marsh – commit 7b4986a
http://github....
Globalcode – Open4education
Interface do framebuffer
Arquivo framebuffer.c – projeto marsh – commit 7b4986a
http://github....
Globalcode – Open4education
Implementação selecionável
A implementação é escolhida na compilação, pelo
Makefile.
Todas imp...
Globalcode – Open4education
Organização de pastas para
código multi-plataforma
Código dependente de plataforma
Código inde...
Globalcode – Open4education
Organização de pastas
Arquivos de implementação
são escolhidos de acordo
com o target do Makef...
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));...
Globalcode – Open4education
Usando o framebuffer
#include “framebuffer.h”
framebuffer_init();
...
pixel_t * fb_point = fra...
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...
Globalcode – Open4education
Projeto Marsh e Projeto Chelper
Ambos são exemplos das técnicas de modularidade apresentadas.
...
Globalcode – Open4education
Muito obrigado!
Dúvidas?
felipelav no gmail
9 ago 2014 44 / 44Modularização de Código C
Próximos SlideShares
Carregando em…5
×

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

966 visualizações

Publicada em

Apresentação feita dia 09/08/2014 na TDC de SP sobre modularidade de código C.

Publicada em: Tecnologia
  • Seja o primeiro a comentar

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

  1. 1. 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
  2. 2. Globalcode – Open4education Experiência do Apresentador http://www.embarcados.com.br 9 ago 2014 2 / 44Modularização de Código C
  3. 3. 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
  4. 4. 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
  5. 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. 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. 7. Globalcode – Open4education Porque modularizar 9 ago 2014 7 / 44Modularização de Código C
  8. 8. 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
  9. 9. 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
  10. 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. 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. 12. Globalcode – Open4education Quatro regras da modularização proposta 9 ago 2014 12 / 44Modularização de Código C
  13. 13. 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
  14. 14. Globalcode – Open4education A composição do módulo 9 ago 2014 14 / 44Modularização de Código C
  15. 15. 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
  16. 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. 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. 18. 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
  19. 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. 20. Globalcode – Open4education Usando o módulo “rectangle” 9 ago 2014 20 / 44Modularização de Código C
  21. 21. 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
  22. 22. 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
  23. 23. 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
  24. 24. Globalcode – Open4education Demais tipos de módulos propostos 9 ago 2014 24 / 44Modularização de Código C
  25. 25. 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
  26. 26. Globalcode – Open4education Módulo vector (instância na stack) 9 ago 2014 26 / 44Modularização de Código C
  27. 27. 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
  28. 28. 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
  29. 29. 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
  30. 30. 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
  31. 31. Globalcode – Open4education Módulo framebuffer (instância única e implementação selecionável) 9 ago 2014 31 / 44Modularização de Código C
  32. 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. 33. 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
  34. 34. 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
  35. 35. 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
  36. 36. 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
  37. 37. 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
  38. 38. Globalcode – Open4education Usando o módulo vector e framebuffer 9 ago 2014 38 / 44Modularização de Código C
  39. 39. 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
  40. 40. 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
  41. 41. Globalcode – Open4education Referências 9 ago 2014 41 / 44Modularização de Código C
  42. 42. 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
  43. 43. 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
  44. 44. Globalcode – Open4education Muito obrigado! Dúvidas? felipelav no gmail 9 ago 2014 44 / 44Modularização de Código C

×