8

変数のスコープはコンパイラによってどのように実装されますか? つまり、静的変数と言うとき、スコープは、静的変数が定義されている同じファイルで定義されているブロックまたは関数に限定されますか? これはマシンレベルまたはメモリレベルでどのように達成されますか?

この制限は実際にどのように達成されますか?

このスコープは、プログラムの実行時にどのように解決されますか?

4

3 に答える 3

8

マシンレベルではまったく達成されません。コンパイラは、マシン コードが実際に生成される前にスコープをチェックします。C のルールは、マシンではなく、コンパイラによって実装されます。コンパイラはこれらのルールをチェックする必要がありますが、マシンはチェックしませんし、できません。

コンパイラがこれをチェックする方法の非常に単純な説明:

スコープが導入されるたびに、コンパイラはそれに名前を付けて、他のスコープとの関係でそのスコープの位置を簡単に判断できる構造 (ツリー) に配置し、現在のスコープとしてマークします。変数が宣言されると、現在のスコープに割り当てられます。変数にアクセスすると、現在のスコープで検索されます。見つからない場合は、ツリーを検索して現在のスコープより上のスコープを見つけます。これは、最上位のスコープに到達するまで続きます。それでも変数が見つからない場合は、スコープ違反があります。

于 2012-11-02T17:03:58.150 に答える
1

コンパイラの内部で、その実装が定義されています。たとえば、コンパイラを作成する場合、ツリーを使用して「スコープ」を定義します。これは、間違いなくバイナリ ツリー内のシンボル テーブルになります。

任意の深さのハッシュ テーブルを使用するものもあります。そのすべての実装が定義されています。

于 2012-11-02T16:59:09.370 に答える
0

あなたが求めていることを100%理解しているとは限りませんが、「静的変数と関数が最終プログラムにどのように格納されるか」という意味であれば、それは実装定義です。

つまり、そのような変数や関数を保存する一般的な方法は、他のグローバル シンボル (および一部の非グローバル シンボル) と同じ場所にあります。違いは、これらは「エクスポート」されないため、外部からは見えないことです。私たちのソフトウェアにリンクしようとしているコード。

つまり、次の内容を含むプログラムです。

int var;
static int svar;
int func() { static int func_static; ... }
static int sfunc() { ... }

0xF000...メモリ内に次のレイアウトがある可能性があります(データがで始まり、で機能するとしましょう0xFF00):

0xF000: var
0xF004: svar
0xF008: func.func_static
...
0xFF00: func's data
0xFF40: sfunc's data /* assuming we needed 0x40 bytes for `func`! */

ただし、エクスポートのリストには、エクスポートされたものとも呼ばれる非静的シンボルのみが含まれます。

var   v 0xF000
func  f 0xFF00

繰り返しになりますが、静的データがまだファイルに書き込まれている間 (どこかに保存する必要があります!)、エクスポートされないことに注意してください。簡単に言えば、私たちのプログラムはsvar、などを含むことを誰にも知らせませんsfunc

Unices では、次のツールを使用して、ライブラリまたはプログラムがエクスポートするシンボルを一覧表示できnmます: http://unixhelp.ed.ac.uk/CGI/man-cgi?nm ; Windows 用の同様のツールが存在します (GnuWin32 にも同様のツールがある可能性があります)。

実際には、実行可能コードはデータとは別に保存されることが多く (たとえば、書き込みから保護できるようにするため)、メモリ使用量とキャッシュ ミスを最小限に抑えるために両方が並べ替えられる場合がありますが、考え方は変わりません。

もちろん、最適化を適用することもできます。たとえば、静的関数を呼び出しごとにインライン化することができます。つまり、関数自体のコードはまったく生成されないため、それ自体はどこにも存在しません。

于 2012-11-02T17:13:08.150 に答える