0

静的/動的スコープに関する次の問題で立ち往生しています。

次のプログラムフラグメントは、グローバル変数を許可し、関数のネストされた宣言を許可しないプログラミング言語で記述されています。

 global int i = 100, j = 5; 
 void P(x) { 
  int i = 10; 
  print(x + 10); 
  i = 200; 
  j = 20; 
  print (x); 
 } 
 main() {P(i + j);} 

Q1。プログラミング言語が静的スコープを使用し、必要に応じてパラメーターを渡すメカニズムを呼び出す場合、上記のプログラムによって出力される値は次のとおりです。

(A)115、220(B)25、220(C)25、15(D)115、105

Q2。プログラミング言語が動的スコープと名前による呼び出しパラメーター受け渡しメカニズムを使用する場合、上記のプログラムによって出力される値は次のとおりです。

(A)115、220(B)25、220(C)25、15(D)115、105

私の考え:

Q1:静的スコープであり、必要に応じて呼び出しられるため、xをi+jに置き換える必要があります。ただし、名前iの変数が既に存在するため、ローカル名の競合が発生します。したがって、それ(グローバルi)の名前が変更される可能性があります。たとえば、i1とすると、呼び出しは次のようになります。

   first call: print(x+10) -> (i1 + j + 10) -> (100 + 5 + 10) -> 115
   second call: print(x) -> print(i1 + j) -> 105 (Already evaluated - call by need)

Q2:動的スコープでは、最初にローカル関数で変数を検索し、次にローカル関数を呼び出した関数を検索し、次にその関数を呼び出した関数を検索し、以下同様に呼び出しスタックを検索します。

名前による呼び出しによると:

print (i1 + j + 10) -> print (100 + 5 +10 ) -> 115

そして2番目の呼び出しは

print(x) -> print(i1 + j) -> (100 + 20) = 120 // Evaluate again - Call be name.

この答えは正しいですか?(オプションにはありません)何か足りないものはありますか?(動的バインディングは可能性がありますか?)

4

3 に答える 3

4

Q1

OPの答えは正解です(D)。実際、グローバルiはの実行中に変更されないため、必要による呼び出しと値による呼び出しPに違いはありません。

これが違いを生む例です:

global int i = 100, j = 5;

void IncreaseTheGlobal() {
    i = i + 1;            // static scoping means this is the GLOBAL i!
    print(i);
}

void P(x) {
    int i = 10;
    IncreaseTheGlobal();  // 101 (increased global i)
    print(i);             //  10 (local i)
    print(x);             // 106 (x is evaluated; picks up increased global i)
    IncreaseTheGlobal();  // 102 (2nd time increased global i)
    print(x);             // 106 (x not re-evaluated; unaffected by 2nd increase)
}

main() {
    print(i);             // 100 (original global i)
    P(i + j);
    print(i);             // 102 (new global i)
}

OPがすでに指摘しているように、最初に評価されると、その特定の瞬間にxグローバルが持つ値をすべて取得します。iその最初の評価xの後、グローバルのその後の変更による影響を受けなくなりiます。

Q2

名前による呼び出しは、通常、マクロ言語で使用されます。では、これまでで最もよく知られているマクロ言語であるCプリプロセッサを使用してみませんか?

#include <stdio.h>

int i = 100, j = 5;

#define print(num)  printf("%d\n", num)

#define P(x) {     \
    int i = 10;    \
    print(x + 10); \
    i = 200;       \
    j = 20;        \
    print(x);      \
}

main() {
    P(i + j);
}

コンパイル、実行、および参照:25、220。

名前による呼び出しは、単純な検索と置換で機能します。の本文内で、のすべての出現箇所を。Pに置き換えます。xi + j

int i = 10; 
print(i + j + 10);    // 10 + 5 + 10 = 25
i = 200;
j = 20;
print(i + j);         // 200 + 20 = 220

言い換えれば、ij内部は、評価されたi + jときにスコープ内にあるものすべての現在価値を取得するだけです。x

正解はBですよね?まあ、ほとんど...正しい答えはの実装に依存しますprintprintプラクティスも名前で呼び出し、独自のローカル変数を定義するとすると 、結果が劇的に変化します。これを試して:printi

#define print(num)  { int i = 0; printf("%d\n", num); }

結果は15、20に変わります。

これはおそらく、動的スコープがコードの保守性に悪い理由の最も重要な理由です。関数の実装変更print(ローカル変数の名前を変更するような些細なことでも)は、より高いレベルで関数を壊す可能性があります。

于 2014-02-02T12:28:56.053 に答える
0

名前による呼び出しである2番目の部分で

行i=200は、ローカルiを更新します

これで、print(x)が呼び出されている間、print(i + j)=> print(200 + 20)=>220に置き換えられます。

于 2013-02-08T15:49:12.377 に答える
0

Q1の場合:

int i = 10; 
print(x + 10); // print (i + j + 10); prints 10 + 5 + 10 = 25; local i gets used here

i = 200; 
j = 20; 

print (x); // print (i + j); call by need ensures, no reevaluation and i + j is 15. 

だから、答えはC-25、15です

于 2015-04-22T22:35:07.160 に答える