Domanda

Questo post riferimento alla Regola One Definizione.

Wikipedia è piuttosto male a spiegare come implementarlo

Dove posso trovare buone le risorse sulle linee guida da seguire in C ++ .NET?

È stato utile?

Soluzione

La regola una definizione sostanzialmente significa che un / funzione variabile può essere posizionato solo in un punto nello spazio degli indirizzi dell'eseguibile compilato. Un modo di pensare è mentre si compila, v'è una serie di memoria da utilizzare nel programma compilato (codice oggetto), e una tabella di ricerca per fare riferimento posizioni / funzione variabile. Questo viene fatto a livello di singolo processo. Supponiamo che il seguente è un semplice programma:

file1.cpp

int square(int x); // this is a declaration
extern int someVariable; // this is a declration

void square(int x)  // this is a definition
{
    return x * someVariable;
}

file2.cpp

int square(int x); // this is a declaration

int someVariable; // this is a definition    
void main()
{
    someVariable = 12;
    someVariable = square(4);
}       

Quando il compilatore inizia la compilazione del codice oggetto, si legge nelle dichiarazioni, e mette cosa al suo tavolo. Alla fine della compilazione file1.cpp, finirà con qualcosa di simile:

declarations:
    square (XX): function that returns int, and takes a single int as parameter [4 bytes]
    someVariable (YY): integer [4 bytes]
data:
    12 34 56 78 aa XX XX XX XX ab cd
definition:
    square: starts at address 0

Questo presuppone che la funzione viene compilato per quei particolari istruzioni di montaggio. Al momento linker, XX XX XX XX otterrà sostituito con l'indirizzo del someVariable.

File2 finisce qualcosa del tipo:

declarations:
    square (XX): function that returns int, and takes a single int as parameter [4 bytes]
    someVariable (YY): integer [4 bytes]
data:
    00 00 00 00 12 34 56 78 12 34 56 YY YY YY YY 23 21
definitions:
    someVariable: starts at address 0
    main: starts at address 4

E in questo caso, la YY sarà sostituito dall'indirizzo del quadrato.

Ecco dove il linker entra in gioco. Il lavoro del linker è quello di passare attraverso la lista, e costruire un tavolo di dove tutto è nello spazio di indirizzi del programma in fase di compilazione. Tuttavia, v'è un problema se due file oggetto hanno la stessa definizione di una variabile quando tenta di collegarsi. Se ci fossero due definizioni di someVariable nell'esempio di cui sopra, allora non saprebbe cosa per sostituire YY con. Allo stesso modo, se c'è non definizione, quindi si ottiene errori del linker brutte.

La "soluzione" alla regola è quella di partizionare il file in modo che si dispone di definizioni solo nei file cpp, e hanno le dichiarazioni di cose nei file .h, quindi l'esempio precedente diventerebbe:

file1.cpp

#include "file2.h"

void square(int x)  // this is a definition
{
    return x * someVariable;
}

file1.h

int square(int x); // this is a declaration

file2.cpp

#include "file1.h"

int someVariable; // this is a definition    
void main()
{
    someVariable = 12;
    someVariable = square(4);
}

file2.h

extern int someVariable;

Si noti che questo è un esempio incredibilmente semplice, e che essa non si applica in realtà in .NET dal momento che non v'è un concetto di una distinzione tra una dichiarazione e la definizione.

Altri suggerimenti

Il modo più semplice per rispettare la regola quella definizione è di mettere la definizione in un file cpp invece che l'intestazione.

La gente a volte mettono le definizioni nelle intestazioni che utilizzano le macro e / o condizionali preprocessore per rendere l'oggetto o la funzione definita in un solo unità di compilazione. Ma è più facile di solito (e certamente più comprensibile) di mettere solo la definizione in un file cpp.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top