PDA

Visualizza la versione completa : [C++] Diversi tipi di header


VisRoboris
17-03-2011, 10:54
Salve a tutti :D
Potreste spiegarmi che differenza c'è nell'utilizzare queste due tipologie di header?
tipologia 1:
file header.h

#ifndef HEADER
#define HEADER

int AggiungiUno(int* a) {*a++;}

#endif

tipologia 2:
file header.h

int AggiungiUno(int*);
file header.cpp


#include "header.h"
AggiungiUno(int* a) {*a++;}

YuYevon
17-03-2011, 11:52
Negli header file non va *mai* scritto codice di funzioni o metodi (a parte quelli inline di una classe). Dato che le direttive #include non fanno altro che includere fisicamente il file specificato all'interno del file sorgente, immagina cosa succederebbe se ad esempio in stdio.h fosse definito il codice di tutte le sue funzioni: anche per un semplice "hello world" che utilizza solo una banale printf(), dovresti ricompilare tutto il codice della libreria!
Negli header file ci vanno solo le dichiarazioni di funzione, classi, tipi di dato ed eventuali direttive al preprocessore, mentre il codice va definito in appositi file sorgente con estensione c/cpp o quello che è (in pratica, il secondo esempio che hai postato).

Ah, per inciso: per motivi di associatività di operatori, *a++ non incrementa di uno il valore puntato da 'a', ma incrementa il puntatore 'a' e poi lo dereferenzia (inutilmente), quindi non solo non dà il risultato desiderato ma può anche essere causa di violazione di accesso alla memoria. Sostituisci con (*a)++;

VisRoboris
17-03-2011, 16:24
Pensavo che mettendo il codice dell'header tra:
#ifndef HEADER
#define HEADER

e #endif venisse comunque eseguito una sola volta, indifferentemente da quante
volte viene incluso..

YuYevon
17-03-2011, 17:17
Quelle sono #include guard (http://en.wikipedia.org/wiki/Include_guard) e servono per evitare inclusioni multiple di header file (e conseguentemente ridefinizioni di strutture o classi). Resta comunque il concetto che negli header file non vanno implementati metodi o funzioni, ma solo dichiarati.

MItaly
17-03-2011, 17:22
Originariamente inviato da VisRoboris
Pensavo che mettendo il codice dell'header tra:
#ifndef HEADER
#define HEADER

e #endif venisse comunque eseguito una sola volta, indifferentemente da quante
volte viene incluso..

Che c'entra? Gli header guards evitano che il contenuto del .h venga ripetuto più volte se il .h viene incluso più volte nello stesso .cpp (cosa che può capitare ad esempio se includi direttamente il .h e magari un altro .h che lo include a sua volta), ma se inserisci il corpo della stessa funzione in più file .cpp il linker, al momento di riunire i vari moduli oggetto in un unico eseguibile, si ritroverà con più definizioni della medesima funzione, e non saprà quindi quale scegliere. Il divieto di avere più di una definizione della medesima funzione è la cosiddetta One Definition Rule (http://en.wikipedia.org/wiki/One_Definition_Rule) (ODR).

Questa restrizione non si applica alle funzioni inline e template, che vengono marcate in modo particolare dal compilatore in modo che il linker, anche se ne trova più di una con stesso nome e signature, ne scelga una qualunque (suppone che siano tutte uguali).

In ogni caso, il formato "normale" degli header è:


// header.h
#ifndef HEADER_H_INCLUDED
#define HEADER_H_INCLUDED

int AggiungiUno(int* a);

#endif


// header.cpp
#include "header.h"

int AggiungiUno(int* a)
{
(*a)++;
}

In questa maniera si evitano sia i problemi derivanti dall'inclusione multipla che le definizioni duplicate.

Tra parentesi, sarebbe meglio, rispetto a HEADER, usare una cosa del tipo HEADER_H_INCLUDED, in modo da diminuire il rischio di collisioni con altri nomi o macro; alcuni usano iniziare i nomi degli include guard con degli underscore, ma è pessima pratica, dato che i nomi che iniziano per underscore seguito da maiscola sono riservati per il compilatore in ogni scope.

VisRoboris
17-03-2011, 17:33
Ho capito finalmente, grazie a tutti ;D

Loading