Jump to content
PsySc0rpi0n

Esquema de includes em files .c e .h

Recommended Posts

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...

Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.