|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
[C] Variabili globali e header files
Sto facendo un programma in cui ho la necessità di utilizzare più *.c file e 1 *.h file .
Il programma necessità di una variabile globale. Mi sono imbattuto però nel problema che dichiarandola e definendola nel file *.h ( incluso in TUTTI i file *.c ) il linker mi dice che la variabile è dublicata. Ho cercato un po' su internet e ho visto che non sono stato l'unico ad avere questo problema. Ho trovato una soluzione ma non mi sono ben chiari alcuni concetti:
Detto questo, è corretto questo modo di dichiarare variabili globali in file header inclusi in più *.c file? C'è un modo migliore? Inoltre, cosa significano: Codice:
#ifndef _NOMEHEADER_H_ #define _NOMEHEADER_H_ ... #endif
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2783
|
Mi sembra di ricordare che per avere una variabile globale la devi dichiarare normalmente in uno dei file .c e in tutti gli altri dichiararla come extern.
Codice:
#ifndef _NOMEHEADER_H_ #define _NOMEHEADER_H_ ... #endif |
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
allora diciamo che questa:
Codice:
int var; questa invece: Codice:
extern int var; la definizione deve essere una sola, le dichiarazioni possono essere tante, per cui la soluzione che si utilizza di solito è inserire le dichiarazioni nei file header, che possono essere incluse quante volte si vuole (nel senso in quanti file vuoi) |
|
|
|
|
|
#4 | |
|
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Quote:
Codice:
/*header.h*/
int myVar;
/*file1.c*/
#include "header.h"
[...]
void changeIt()
{
myVar = 1;
}
[...]
/*file2.c*/
#include "header.h"
[...]
int main()
{
changeIt();
printf("%d\n", myVar);
return (0);
}
[...]
Ricorda che alla direttiva "extern" devono seguire tutti gli attributi della variabile "originale", se per esempio dichiari la variabile "originale" con la keyword "volatile", a seguito della keyword "extern" dovrai far sempre seguire anche la keyword "volatile" (oltre al tipo e al nome della variabile). E cosi via. L'uso delle direttive del preprocessore Codice:
#ifndef SOMETHING_H #define SOMETHING_H #endif Dice al precompilatore (in fase di precompilazione e quindi quando un file deve essere incluso in un'altro file) esattamente: - se non esiste alcuna definizione della macro SOMETHING_H - dichiara SOMETHING_H - includi il corpo dello header - fine Se dopo Codice:
#endif Anche se spesso si assume che la include guard permetta di impedire l'inclusione del file .h se la macro è già presente, questo non è corretto. Il precompilatore, infatti ogni volta include il file .h ed analizza la condizione, se la condizione è vera include il corpo, altrimenti include il file comunque ma escludendo tutto quello che c'è tra #ifndef e #endif (nel nostro caso un file vuoto se non specifichiamo altro prima di #ifndef o dopo #endif). Alcuni compilatori supportano la direttiva Codice:
#pragma once Nel caso questa direttiva non sia supportata viene semplicemente ignorata (non sono mai venuto a conoscenza di compilatori che segnalano errori per una direttiva pragma non supportata). Volendo potresti mescolare la direttiva pragma e la include guard per supportare tutti i compilatori e al tempo stesso sfruttare l'ottimizzazione dei compilatori che supportano la suddetta pragma. esempio: Codice:
#ifndef FILE_H #define FILE_H #pragma once #endif /*FILE_H*/ Ciao!
__________________
Ultima modifica di Opcode : 10-12-2010 alle 01:09. |
|
|
|
|
|
|
#5 | ||||||
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Quote:
Quote:
Ovvero, nell'header H Codice:
extern int variabile; Codice:
int variabile; Quote:
Quote:
Quote:
Quote:
Codice:
#ifndef HEADER_H_ #define HEADER_H_ int variabile_globale; #endif Quale è meglio? Usare extern? O l'ifndef?
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
||||||
|
|
|
|
|
#6 |
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2783
|
Mi sa che hai fatto un po' di confusione. Direi che tuccio ha spiegato molto chiaramente l'uso di extern, prova a rileggere meglio il suo post.
E su #ifndef e #define provo a farti un esempio. Tanto per cominciare bisogna sapere che la direttiva #include non fa altro che sostituire l'istruzione #include con il contenuto del file specificato. Detto questo guarda questo esempio (stupido ma esplicativo): Codice:
// file header.h int var; // file header2.h #include "header.h" // file source.c #include "header.h" #include "header2.h" Usando ifndef e define: Codice:
// file header.h #define _HEADER_ int var; // file header2.h #ifndef _HEADER_ #include "header.h" #endif // file source.c #ifndef _HEADER_ #include "header.h" #endif #include "header2.h" Ovviamente puoi mettere #ifndef e #define un po' dove ti pare purché abbia senso, io ho messo define in header.h invece che subito dopo #ifndef. Ultima modifica di wingman87 : 10-12-2010 alle 18:03. Motivo: Errore di battitura |
|
|
|
|
|
#7 |
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Bene, però sia usando il metodo che ho spiegato all'inizio, sia questo dell'ifndef, ottengo lo stesso risultato, ovvero di poter dichiarare una variabile globale in un header e utilizzare lo stesso header in più file.
La mia domanda ora è: quale metodo conviene utiizzare? Quale, dal punto di vista dell'ottimizzazione, è migliore?
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|
|
|
|
|
#8 |
|
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Ovviamente devi aggiungere ai file gli header necessari ed esportare il prototipo della funzione changeIt affinchè funzioni, io ti ho riportato solo le parti di interesse.
[edit] La risposta alla tua domanda stà nel design della tua applicazione e come/dove usi la variabile.
__________________
|
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2783
|
Per avere una variabile globale devi fare come ti dicevo nel mio primo post e come diceva anche tuccio. La definisci in un solo file e in tutti gli altri la dichiari con la parola chiave extern. Se poi la definisci/dichiari direttamente o indirettamente (cioè definendola/dichiarandola in un header e poi includendolo) non è rilevante, la cosa importante è che poi fai le inclusioni giuste.
Il discorso su ifndef e define è un discorso a parte. |
|
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2783
|
A me quell'esempio non sembra corretto perché file1.c e file2.c definiscono 2 istanze diverse della variabile myVar.
|
|
|
|
|
|
#11 | |
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Quote:
Inoltre usando l'ifndef risolvo il problema. Certo aggiungendo ora nel main: Codice:
extern int max_game_time; Ora, immagino funzioni uguale anche se io tolgo gli ifndef, però se si dovesse fare una comparazione, è meglio, a livello di risorse, usare l'ifndef e includere il file H dentro tutti i file C o dichiarare la variabile normalmente nel file H ( senza ifndef ) e dichiarla extern in tutti i file C?
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|
|
|
|
|
|
#12 | |
|
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Quote:
A livello di "risorse" non ti cambia proprio nulla. Allochi sempre e solo una variabile. L'IFNDEF non ha niente a che fare con la dichiarazione di una variabile, è un meccanismo di sicurezza per evitare errori dovuti ad una doppia inclusione dello stesso file header.
__________________
Ultima modifica di Opcode : 10-12-2010 alle 22:35. |
|
|
|
|
|
|
#13 |
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2783
|
|
|
|
|
|
|
#14 |
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Da quel che ne deduco, in questo caso non fa differenza il modo con cui si ottiene il risultato ( ovvero avere una variabile globale in un header incluso in più file C ) visto che, da quel che mi dite, le risorse allocate sono sempre uguali.
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|
|
|
|
|
#15 | ||
|
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Quote:
Se vuoi vederci meglio su linux prova a compilare con la flag -E per vedere come si comporta il precompilatore, e con -S ti puoi studiare il codice assembly prodotto, vedi che l'asm dichiara la variabile nel file del main. Quote:
Il mio era un esempio sfruttabile con i recenti compilatori, se provi funzionerà anche su gcc con le flag -pedantic -ansi -Wall per il comportamento descritto sopra. Se definisci la variabile con un valore nello header avrai un problema se importi lo header in altri file, ma se la definisci senza valore o dichiari con la keyword extern non avrai problemi (sulla multipla definizione non sò quali compilatori e da che versione la supportino, ma è una cosa che và già da almeno un paio di anni a questa parte). E comunque sei sicuro che la variabile viene sempre e solo allocata una volta, perchè altrimenti ci sarebbe una corrispondenza dell'identificatore nella tabella dei simboli che causerebbe un errore per multipla definizione.
__________________
|
||
|
|
|
|
|
#16 |
|
Senior Member
Iscritto dal: Nov 2005
Messaggi: 2783
|
Grazie per le informazioni. Era quello che sospettavo. Ad ogni modo non mi sembra buona pratica sfruttare questa feature del compilatore. Inoltre usando extern possiamo accorgerci di eventuali errori nel caso in cui senza accorgercene dichiariamo la variabile con un nome leggermente diverso. E possiamo anche inizializzare la variabile laddove è definita.
|
|
|
|
|
|
#17 |
|
Senior Member
Iscritto dal: Jul 2003
Città: Alessandria
Messaggi: 10167
|
Grazie a tutti, tutto chiaro!
__________________
Dell XPS 13 (9350) :: i5-2500K - HD6870 - AsRock Z68 Pro3 - Corsair Vengeance 8GB (4x2) DDR3 :: Samsung Galaxy S4 GT-i9505
|
|
|
|
|
|
#18 |
|
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Di nulla =))
...quando si può fà piacere condividere. Ciao e buona serata ad entrambi.
__________________
|
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 16:02.




















