Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

PsySc0rpi0n

Esquema de includes em files .c e .h

Mensagens Recomendadas

PsySc0rpi0n

Boas...

Ando de novo a tentar perceber como funciona a divisão de código por vários ficheiros e tenho a seguinte dúvida:

Tenho um ficheiro que lida com a entrada de dados do utilizador, ou seja, pede os dados ao utilizador, digamos input.c e que tem o respectivo input.h ende estão os protótipos das funções.

Depois tenho o fichero (main.h) main.c que interage com o utilizador mostrando mensagens como "Introduça uma das opções" e de seguida preciso de chamar uma das funções do ficheiro input.c.

No ficheiro main.c, tenho que fazer o include apenas do input.h ou tenho que fazer apenas do input.c? É que estou com esta dúvida porque normalmente fazem-se includes apenas de ficheiros .h e não de ficheiros .c, mas neste caso eu preciso de usar uma função que está no ficheiro input.c cujos protótipos de funções estão no input.h...

Editado por PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

dois pontos fundamentais :

- .h >> só protótipos

- .c >> implementação das funções dos protótipos declarados no respectivo .h (e mais se necessitares)

agora, nos .c fazes include de todos os .h (nunca .c) onde estão declarados os protótipos da funções que necessitas/usadas no ficheiro .c


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Vi que me enganei a escrever no post anterior.

Mas o que eu queria perguntar é se o main.c tem acesso às funções do input.c através do input.h

Ou seja:

main.c

#iclude "main.h"
#include "input.h"
int main(){
 ...
 func1();//função presente em input.c com o seu protótipo em input.h
 ...
}

input.c

#include "input.h"
int func1(){
 //to do stuff
}

input.h

int func1();


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

o compilador ao processar o main.c, irá ler o input.h e assumirá que a função func1 existe, não dando erro.

se a função existe na aplicação final é da responsabilidade do linker que irá juntar os ficheiros objectos


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Estou a tentar de novo outro pequeno projecto mas no momento de compilar com o make, dá um montão de erros que eu não sei se acontecem por causa de includes mal feitos ou se acontecem devido mesmo a erros do código.

Quando tento compilar um programa de um só ficheiro nunca recebo erros deste tipo:

http://pastebin.com/12b0ZET6

Refiro-me a essas colunas compridíssimas. Os restantes erros não sei se têm a ver também com estas colunas ou não.

Sintetizando:

2 pastas - src e include

src - main.c, menus.c, input_option.c, array_int_control.c, array_str_control.c

include - main.h, menus.h, input_option.h, array_int_control.h, array_str_control.h, error_handler.h

Os ficheiros .c apenas têm o include dos respectivos files .h e do error_handler.h.

O Makefile está assim:

CC := gcc
CFLAGS := -Wextra -Wall -pedantic -std=c99 -Iinclude
#OBJECT FILES
obj/%.o: src/array_int_control.c src/array_str_control.c src/main.c src/menus.c src/input_option.c | obj
   $(CC) -o $@ $(CFLAGS) $^
#BIN FILE
bin/array_control: obj/array_int_control.o obj/array_str_control.o obj/main.o obj/menus.o obj/input_option.o | bin
   $(CC) -o $@ $(CFLAGS) $^
obj bin:
   mkdir obj bin
clean:
   rm -rf obj
   rm -rf bin
.PHONY: clean


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

o problema está claramente na dependência circular.

1º - considero que teres dependências circulares é uma demonstração directa de falta de estruturação do código.

2º - o que quero dizer com dependências circulares:

////////////////////////////
// ficheiro : header1.h
////////////////////////////

// as definições do ficheiro "header2.h" são necessárias para avaliar o ficheiro "header1.h"
#include "header2.h"


////////////////////////////
// ficheiro : header2.h
////////////////////////////

// as definições do ficheiro "header1.h" são necessárias para avaliar o ficheiro "header2.h"
#include "header1.h"

conclusão, o compilador vai andar como uma pescadinha de rabo na boca ... ora salta para header1.h ora salta para header2.h

3º - deverias usar código para combater dependências circulares e múltiplas declarações devido a múltiplas inclusões:

(sim múltiplas inclusões como teres header1.h que faz inclusão de header2.h e header3.h, e o header2.h voltar a fazer a inclusão de header3.h. isto dá directamente erro do compilador por múltiplas definições dos conteúdos do header3.h)

////////////////////////////
// ficheiro : header1.h
////////////////////////////
#ifndef HEADER1_H
#define HEADER1_H

// inclusões dos ficheiros necessários
#include "header2.h"

// as definições do ficheiro "header1.h"

#endif /* HEADER1_H */

este tipo de código (do pré-compilador) impede as reavaliação do código porque nota:

- se o valor HEADER1_H ainda não estiver definido (#ifndef), então define-o (#define). logo, nunca mais entrará no if, mesmo que a árvore de dependências volte a fazer inclusão do ficheiro tratado.


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Pois... É isso que tenho andado a tentar compreender...

Qual das duas é a melhor prática para a melhor estruturação/divisão de código:

1 - Deixar as definições de funções e interacção como utilizador nos files .c e em cada um incluir um file .h respectivo e neste colocar todos os includes necessários, defines, include guards e assinaturas das funções usadas no file .c,

ou

2 - incluir nos files .c os #includes dos headers files nativos do C, #defines necessários localmente (necessários apenas para o ficheiro .c) e deixar eventuais #includes de headers files criados por nós, eventuais #defines necessários ao file .h e assinaturas das funções usadas no file .c????


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

dois pontos fundamentais :

- .h >> só protótipos

- .c >> implementação das funções dos protótipos declarados no respectivo .h (e mais se necessitares)

agora, nos .c fazes include de todos os .h (nunca .c) onde estão declarados os protótipos da funções que necessitas/usadas no ficheiro .c


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Então como faço no seguinte exemplo:

Tenho o main.c onde apenas tenho mensagens para o utilizador e depois chamo 2 funções que estão no file string.c. Estas duas funções, uma delas pede uma string ao user e a outra mostra essa string no ecrã...

Ora tenho que declarar uma variável para guardar essa string e estou a fazê-lo no file main.c mas preciso de #define uma constante que será o tamanho máximo da string. Este define coloco-o em que ficheiro? No main.c, string.c ou string.h? E depois preciso de fazer #include do ficheiro que tem essa constante tanto no main.c como no string.c...


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

mas preciso de #define uma constante que será o tamanho máximo da string. Este define coloco-o em que ficheiro?

em absolutamente lado nenhum

/////////////////////////////////
// string.h
/////////////////////////////////

int request_string(char * string, int size);
int show_string(char * string);

/////////////////////////////////
// string.c
/////////////////////////////////
#include "string.h"

#include <string.h>
#include <stdio.h>

int request_string(char * string, int size) {
 int strlength = 0;

 printf("escreva a string : ");
 fflush(stdout);

 if (fgets(string, size, stdin) == NULL)
   return -1;

 strlength = strlen(string);
 if (string[strlength + 1] == '\n')
   string[strlength + 1] = 0;

 return 0;
}

int show_string(char * string) {
 printf("A string inserida : %s\n", string);
}

/////////////////////////////////
// main.c
/////////////////////////////////
#include "string.h"

int main(int argc, cha ** argv) {
 char string[256];

 if (request_string(string, 256) == 0) {
   show_string(string);
 }

 return 0;
}


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
PsySc0rpi0n

Hum, ok... Mas não tinhas dito o outro dia que as mensagens da interacção com o utilizador deveriam ficar fora das funções e deixá-las no main.c ou percebi mal?


Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
HappyHippyHippo

o que eu disse (acho eu porque não faz sentido não ser) é :

- ter as funções de interação com utilizador separadas com as de manipulação/gestão dos dados


IRC : sim, é algo que ainda existe >> #p@p

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.