Follow along with the video below to see how to install our site as a web app on your home screen.
Nota: This feature may not be available in some browsers.
include
, dove vado ad inserire i vari file headers.folder/src/*.c
e folder/include/*.h
. Se hai tanti file e li devi organizzare in base alla funzione che svolgono (magari alcuni si occupano di determinate operazioni e altre di altre ancora) puoi dare nomi esplicativi alla cartelle; del tipo che invece di "src" la chiamerai "pippo" o "pluto".- src
- include
- bin
- obj
makefile
#ifndef tuoinclude_h
#define touinclude_h
.....
#endif /* tuoinclude_h */
Cos'è il make file?Si come dice dispatch, io (linux/gcc) utilizzo una struttura del tipo
Codice:- src - include - bin - obj makefile
CFLAGS += -Iinclude
nel tuo progetto in genere is usa
#include <header_libreria.h>
#include "header_tuo.h"
negli header usa sempre gli include guard:
Codice:#ifndef tuoinclude_h #define touinclude_h ..... #endif /* tuoinclude_h */
Diciamo di si, a volte i task sono creati on the fly e poi rimossi, dipende dall'IDE.Uso visual studio code, però mi sembra che comunque ci siano tipo tasks.json e lunch.json, sono simili al make file?
Rieccomi, sono tornato in citta' e ho organizzato i files cosi:Si come dice dispatch, io (linux/gcc) utilizzo una struttura del tipo
Codice:- src - include - bin - obj makefile
CFLAGS += -Iinclude
nel tuo progetto in genere is usa
#include <header_libreria.h>
#include "header_tuo.h"
negli header usa sempre gli include guard:
Codice:#ifndef tuoinclude_h #define touinclude_h ..... #endif /* tuoinclude_h */
include:
test.h
src:
main.c
test.c
int sum(int, int);
#include "include/test.h"
int sum(int x, int y) {
return x + y;
}
#include <stdio.h>
#include "include/test.h"
int main() {
int x = sum(6, 6);
printf("%d", x);
return 0;
}
gcc src/main.c src/test.c -o main
prova a compilare solo src/main.c e poi compila src/test.cRieccomi, sono tornato in citta' e ho organizzato i files cosi:
Codice:include: test.h src: main.c test.c
test.h
C:int sum(int, int);
test.c
C:#include "include/test.h" int sum(int x, int y) { return x + y; }
main.c
C:#include <stdio.h> #include "include/test.h" int main() { int x = sum(6, 6); printf("%d", x); return 0; }
Ho provato a compilare ma non funziona:
gcc src/main.c src/test.c -o main
come mai?
Da errore a entrambi, ho quindi provato cosi:prova a compilare solo src/main.c e poi compila src/test.c
#include "..\include\test.h"
#include "include\test.h"
undefined reference to `sum'
quando compilo main.cundefined reference to `WinMain@16'
quando compilo test.cDevi generare i soli file oggetto di tutti i moduli con estensione *.c, a questo punto colleghi i file oggetto e generi l'eseguibile:Da errore a entrambi, ho quindi provato cosi:
#include "..\include\test.h"
invece di:
#include "include\test.h"
e mi da un errore diverso:
undefined reference to `sum'
quando compilo main.c
undefined reference to `WinMain@16'
quando compilo test.c
gcc -c file1.c file2.c file3.c ecc..
Genera i file ogetto
gcc -o Nome eseguibile file1.o file2.o ecc.
Genera l'eseguibile
#ifndef MACRO_MODULO
#define MACRO_MODULO
//dichiarazioni
#endif
come dici tu mi funziona ma non credo di aver capito bene l'ultimo argomento:Devi generare i soli file oggetto di tutti i moduli con estensione *.c, a questo punto colleghi i file oggetto e generi l'eseguibile:
Non c'è bisogno di generare i file ogetto per gli header (estensioni .h), in quanto contengono le sole dichiarazioni delle funzioni e delle macro, non istruzioni.Codice:gcc -c file1.c file2.c file3.c ecc.. Genera i file ogetto gcc -o Nome eseguibile file1.o file2.o ecc. Genera l'eseguibile
PS: è importante far si che il modulo anche se incluso più volte non generi errori di "simboli ridefiniti", in quanto includendo più volte lo stesso modulo ridefinirai più volte le stesse macro e le stesse funzioni, per evitare ciò esegui dei controlli sulle macro definite dal modulo tramite le direttive preprocessore, in questo modo se una macro è stato già definita il modulo verrà incluso ma il uso contenuto sarà nullo.
Così le varie macro e funzioni verrano definite solamente se la macro definita dal modulo non è stata ancora definita.Codice:#ifndef MACRO_MODULO #define MACRO_MODULO //dichiarazioni #endif
#ifndef MACRO_MODULO
#define MACRO_MODULO
//dichiarazioni
#endif
come dici tu mi funziona ma non credo di aver capito bene l'ultimo argomento:
C:#ifndef MACRO_MODULO #define MACRO_MODULO //dichiarazioni #endif
ifndef
significa proprio "if not defined".# makefile non testato
CC=gcc
BIN=tuoprog
# percorsi relativi
SRCDIR=src
INCDIR=include
OBJDIR=obj
BINDIR=.
SRCS:=$(wildcard $(SRCDIR)/*.c)
OBJS:=$(patsubst %.c,%.o,$(SRCS))
OBJS:=$(patsubst $(SRCDIR)%,$(OBJDIR)%,$(OBJS))
# qui usi i C/LDFLAGS che vuoi
CFLAGS=-c -pipe -fomit-frame-pointer -Wall -O0 -ggdb -std=c99 -D_XOPEN_SOURCE=500
LDFLAGS=
.PHONY: all $(library)
all: $(BINDIR)/$(BIN)
$(BINDIR)/$(BIN): $(OBJS)
$(CC) $(LDFLAGS) $(OBJS) -o $@
$(OBJDIR)/%.o: $(SRCDIR)/%.c | $(OBJDIR)
$(CC) -I$(INCDIR) $(CFLAGS) $< -o $@
$(OBJDIR):
mkdir -p $(OBJDIR)
clean:
rm $(OBJS)
rm $(BIN)
.
├── bin
│ └── projectname
├── Makefile
├── README.md
├── projectname
│ ├── main.c
│ ├── foo.h
│ ├── foo.c
│ ├── something
│ │ ├── bar.h
│ │ └── bar.c
└── test
├── foo.c
└── bar.h
.
├── list
│ ├── vector.h
│ ├── vector.c
│ ├── array.h
│ ├── array.c
│ ├── linkedlist.c
│ └── linkedlist.h
└── ...
Quello che vuoi scrivere nel codice è più importante di dove vuoi posizionare le directory. Se metti i .h nella stessa directory dei .c ti basta unDa errore a entrambi, ho quindi provato cosi:
#include "..\include\test.h"
#include "test.h"
secco. Altrimenti, se fai come ti hanno suggerito gli altri, ti conviene compilare con qualcosa del tipo gcc -I ./include ./src/pippo.c
e andare di #include <test.h>
.Non funziona... ma qual'è l'errore? Realisticamente dovresti risolvere leggendo la parte precedente del messaggio mio messaggio... o facendo quel che ti ha detto kernelspace.Ho provato a compilare ma non funziona:
gcc src/main.c src/test.c -o main
come mai?
Penso che il tuo modo di organizzare i file sia piu' comodo per includere i file, anche perche' cosi' non mi da errori.Come avrai capito non c'è uno standard né una convenzione più diffusa di altre. L'importante è che quando scrivi un progetto mantieni uno stile consistente. Io non dividerei i .h dai .c se non c'è la necessità di distribuire solo l'interfaccia (e.g., se devi scrivere una libreria closed-source). Solitamente faccio una cosa di questo tipo
Se voglio guardare o modificare un file .h realisticamente sono anche interessato al file .c ad esso associato, e vice versa, quindi li voglio a portata di mano. Le subdirectory (nell'esempio, something) le faccio quando ha senso raggruppare: se è un progetto c++ faccio un mapping uno ad uno con i namespaces e se è un progetto c può capitarmi di fare una cosa di questo tipoCodice:. ├── bin │ └── projectname ├── Makefile ├── README.md ├── projectname │ ├── main.c │ ├── foo.h │ ├── foo.c │ ├── something │ │ ├── bar.h │ │ └── bar.c └── test ├── foo.c └── bar.h
Codice:. ├── list │ ├── vector.h │ ├── vector.c │ ├── array.h │ ├── array.c │ ├── linkedlist.c │ └── linkedlist.h └── ...
Quello che vuoi scrivere nel codice è più importante di dove vuoi posizionare le directory. Se metti i .h nella stessa directory dei .c ti basta un#include "test.h"
secco. Altrimenti, se fai come ti hanno suggerito gli altri, ti conviene compilare con qualcosa del tipogcc -I ./include ./src/pippo.c
e andare di#include <test.h>
.
In alternativa agli include guards segnalo anche il #pragma once che per progetti su un po' più grandi diventa comodo. Non è standard, ma è ampiamente diffuso e ti evita qualche problema: non è solo syntactic sugar, se hai due file con lo stesso nome (e.g., src/pippo.h e test/pippo.h) fa automaticamente la cosa giusta. Non ho una grande preferenza a riguardo, anche gli include guards non mi dispiacciono, ma visto che li abbiamo menzionati penso che valga la pena citare anche l'alternativa "moderna".
Anche quella roba di compilare in più object files e linkarli successivamente... overrated. Si riducono i tempi di compilazione, ma aumentano le pene. I makefiles li ho sempre odiati e quel che è peggio è che non c'è un'alternativa decente. Ce ne sono un migliaio di alternative e fanno tutte schifo. Pare che il cmake "moderno" (da distinguersi dal cmake per come lo si usava anni fa) sia una delle alternative migliori, soprattutto per progetti c++, ma non mi sono mai degnato di impararlo, quindi ho poco da consigliare. Quando chiamare direttamente il compilatore diventa tedioso uso i makefiles solo perché non devo imparare niente di nuovo... ma ne farei volentieri a meno.
Non funziona... ma qual'è l'errore? Realisticamente dovresti risolvere leggendo la parte precedente del messaggio mio messaggio... o facendo quel che ti ha detto kernelspace.
Vabbé, ma vale la pena capire come funziona questo meccanismo visto che è anche abbastanza didattico.Penso che il tuo modo di organizzare i file sia piu' comodo per includere i file, anche perche' cosi' non mi da errori.
.
├── bin
│ └── main
├── include
│ └── test.h
└── src
├── main.c
└── test.c
// main.c
#include <stdio.h>
#include "../include/test.h"
int main() {
int x = sum(6, 6);
printf("%d\n", x);
return 0;
}
// test.h
#ifndef TEST_H_
#define TEST_H_
int sum(int, int);
#endif // TEST_H_
// test.c
#include "../include/test.h"
int sum(int x, int y) {
return x + y;
}
gcc -o bin/main src/test.c src/main.c
. In alternativa, puoi fare questa cosa qui// main.c
#include <stdio.h>
#include <test.h>
int main() {
int x = sum(6, 6);
printf("%d\n", x);
return 0;
}
// test.h
#ifndef TEST_H_
#define TEST_H_
int sum(int, int);
#endif // TEST_H_
// test.c
#include <test.h>
int sum(int x, int y) {
return x + y;
}
gcc -I./include -o bin/main src/test.c src/main.c
.gcc -I./include -c src/test.c -o obj/test.o
gcc -I./include -c src/main.c -o obj/main.o
gcc obj/main.o obj/test.o -o bin/main