2

この投稿は、One Definition Rule への参照です。

ウィキペディアは、それを実装する方法を説明するのがかなり下手です

C++ .NET で従うべきガイドラインに関する適切なリソースはどこにありますか?

4

2 に答える 2

6

1 つの定義規則とは、基本的に、変数/関数は、コンパイルされた実行可能ファイルのアドレス空間内の 1 つの場所にしか配置できないことを意味します。これを考える 1 つの方法は、コンパイル中に、コンパイルされたプログラム (オブジェクト コード) で使用されるメモリの配列と、変数/関数の場所を参照するためのルックアップ テーブルがあることです。これは、プロセスごとのレベルで行われます。以下が単純なプログラムであるとします。

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);
}       

コンパイラがオブジェクト コードのコンパイルを開始すると、宣言が読み込まれ、テーブルに配置されます。file1.cpp をコンパイルすると、次のようになります。

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

これは、関数がこれらの特定のアセンブリ命令にコンパイルされることを前提としています。リンカ時に、XX XX XX XX は someVariable のアドレスに置き換えられます。

File2 は次のようになります。

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

この場合、YY は正方形のアドレスに置き換えられます。

そこでリンカーの出番です。リンカーの仕事は、リストを調べて、コンパイル時にすべてがプログラムのアドレス空間のどこにあるかのテーブルを作成することです。ただし、2 つのオブジェクト ファイルをリンクしようとしたときに変数の定義が同じであると、問題が発生します。上記の例で someVariable の定義が 2 つある場合、YY を何に置き換えるかがわかりません。同様に、定義がない場合は、醜いリンカ エラーが発生します。

ルールの「解決策」は、.cpp ファイルにのみ定義があり、.h ファイルに宣言があるようにファイルを分割することです。したがって、上記の例は次のようになります。

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;

これは信じられないほど単純な例であり、宣言と定義を区別する概念がないため、.NET には実際には当てはまらないことに注意してください。

于 2008-12-19T02:22:38.760 に答える
1

1 つの定義規則に準拠する最も簡単な方法は、ヘッダーではなく .cpp ファイルに定義を配置することです。

マクロやプリプロセッサ条件を使用してヘッダーに定義を入れて、オブジェクトまたは関数を 1 つのコンパイル単位でのみ定義することがあります。しかし、定義を .cpp ファイルに入れる方が、通常 (そして確かに理解しやすい) 簡単です。

于 2008-12-19T02:04:39.233 に答える