2012-02-05 8 views
1

"c-like"言語用のコンパイラを作成しています。現在、コンパイラはローカルスコープの配列をサポートしています。配列の各要素は、ブラケット表記a[0], a[1],...を使用してアクセスできます。このデータ構造をサポートするために、現在のスコープ内のシンボル、および次に利用可能なメモリ空間のアドレスを追跡するためにシンボルテーブルが使用される。例えばにアクセスするために:スタックの実装を使用してcコンパイラ:配列を関数パラメータとして

int a[5]; int b;

、及び4バイト整列されたメモリを所与:実証するために、以下のコードを検討要素a[1]は、私は、シンボルテーブルは、「A」の各個別要素のアドレスを記憶していない

element = ((index+1) * 4) + a.Address; // a.Address is the address of a, which is stored in the symbol table, and index is 1 in this case.

によるメモリ位置を計算し、各シンボルのシンボルと、のアドレスのみ、次のメモリアドレス。

私は、C言語がローカルスコープの配列に対してスタックベースの実装を使用していると仮定しています。しかし、C言語は関数のパラメータとしてローカル配列をどのように渡すのですか?

foo(int[] a) {}

Cコンパイラは、上記の配列を渡すために、ヒープまたはスタックを使用しますか?

+0

なぜ 'index + 1'ですか? 'a [0]'は 'a'が指しているところとまったく同じであるとは思わない? – Shahbaz

+0

@Shahbaz:そうです、その計算は解説のためのものです---私の実際のコードではなく---正しいものではありません。そう、aは確かにa [0]です。 – dnbwise

+0

興味がある場合は、私の答えにあなたの問題に関するコメントを追加しました。 – Shahbaz

答えて

0

Cでは、配列は関数引数として渡されるとポインタに減衰します。 foo(int a[])foo(int * a)と同じで、最初の要素へのポインタだけが関数呼び出しに "生き残る"。関数呼び出し内のポインタから配列サイズを回復する方法はありません。

+0

関数--- foo(int a [])---配列の長さはわかりません。 C言語はそのことをプログラマに知らせる責任を負いますか? – dnbwise

+0

@dnbwise:そうです。 –

+0

関数を 'sizeof'を使って関数に渡して、関数のサイズを関数のポインタと一緒に渡すことができますが、これは読みやすさのために悪い考えであると考えられます。 –

0

int []aは有効なパラメータではなく、確かにint a[]を意味します。

Cでは、機能と、このフォームに配列を渡すことができない。

void foo(int a[]) { ... } 

これに相当する:

void foo(int *a) { ... } 

Cは常に値を通過し、ポインタaの通常コピーが上に格納されていますスタック

0

(Cに次の属する;お使いの言語のためにそれを変更したい場合は、その後、すべての手段によって、先に行く。)

まず、あなたが関数に配列を渡すことができないことを実現します。あなただけの関数へのポインタを渡すことができますので、あなたが

void f(int a[]) { ... } 

を見たときにそれは私が、私はポインタが渡されると言うことができ、と言ってきたことを今実際に

void f(int* a) { ... } 

とまったく同じですスタック。

1

Cは、その内容ではなくそのアドレスによって関数に配列を渡します。

したがって、関数の引数は実際にはint *であり、送信する値はa.Addressです。


仮想仮説を想像してみましょう。あなたの言語のセマンティクスによって、配列がその内容によって関数に送られる必要があると指示された場合は、スタックを使用する必要があります。これは、関数のパラメータがスタックにあるからです。これは、他の合併症をもたらすこと

注:

int f(int arg1, struct some_struct arg2, float arg3); 

とのこの関数のスタックフレームへのポインタとして、この関数内でいくつかのポインタを呼び出してみましょう:

のは、この関数を考えてみましょう。それをbp(ベースポインタ)としましょう。あなたは配列を送信する場合

ので機能で、あなたはarg1アドレスbp+8(例えば)、arg2にはアドレスbp+12にあり、arg3がアドレスbp+36であるであることを知っているであろう、今

sizeof(struct some_struct) 20されると仮定した場合)内容によっては、この機能はどうですか?

int f(int arg1, int arg2[], float arg3); 

arg1arg2は同じ場所にありますが、どの程度arg3arg3の位置をどのように知っていますか?そのためには、arg2のサイズを知る必要があります。

しかし、これに対する解決策があります。最初の4バイト(または配列が4GBを超える可能性があると思う場合は8バイト)に配列のサイズを格納することができます。次に、内容(サイズを含む)によって配列を安全に渡すことができます。そのような場合、a[i]のアドレスはa.Address+4(or 8)+i*sizeof(*a)となります。

  • 余分なメモリを配列のサイズを維持するために:

    は、あなたが考慮する必要があり、いくつかのトレードオフがあります。以前はCが生まれた時に問題になっていましたが、今はもう問題ではありません。

  • 配列をコピーする必要があるため、関数呼び出し時間が大幅に遅くなります。
  • 実行時にバインドチェックを行うことができるため、より堅牢なコードです。私は個人的にはこれが好きではありませんが、実行が遅くなり、プログラムが配列境界から外に出てはいけません!デバッグモードでは非常に便利なオプションです。
  • より良いsizeof実際に配列のサイズを与える配列の操作。これは、サイズの指定されていない配列を受け取ったばかりの関数に便利です。たとえば、strlenはO(1)となります。
  • 配列の真ん中へのポインタは役に立たないでしょう。マージソートを考えましょう。変数はヒープになり、あなたが唯一のそれへのポインタのアドレスを渡す場合でも
  • などなど
+0

言語設計の提案に感謝します。特に、配列のサイズを最初の4バイトで渡すことについてもう少し詳しく読んだことがあります。私はこれがJava配列が実装されている方法であることを読みました。 – dnbwise

+0

あなたが私の個人的な意見に興味があるなら、私はそれの始めに配列のサイズを保持することは制限的なものだと思う。そのような制限の一例は、配列のどこかへのポインタを持っていて、そのポインタを使って配列にアクセスすることができないということです。 – Shahbaz

0

Cのパラメータは、プログラム・スタック に常にあるので、パラメータはまだスタックになります。 ヒープにするには、メモリ(malloc)を割り当てる必要があります。

btw 数ヶ月前に悲しいことに死んだCデニスリッチーのクリエイターからの「Cプログラミング言語」です。 ここをクリックしてください:http://cg.inf.unideb.hu/eng/rtornai/Kernighan_Ritchie_Language_C.pdf(法的なリンクかどうかわかりませんが、ちょうどそれを検索しました)。 Cに興味があるなら、私はその本を買うだろう、それは価値がある。

関連する問題