7

C でのスコープの正確な意味を理解しようとしていました。私が理解できたのは、スコープがコンパイル時のみに制限されているということです。たとえば、他の関数からローカル変数にアクセスする場合。これにより、コンパイル時エラーが発生します。一方、次のプログラムは正常に動作します。これは、C にはフラットなメモリ モデルがあり、実行時に何にでもアクセスできることを意味します。C の本では、スコープは有効期間と変数の可視性に関連付けられていますが、かなり紛らわしいことがわかりました。これらすべての用語は、コンパイル時にのみ意味があると思います。誰かがそれに光を当てることができますか?

#include "stdio.h"

int *ptr;

int func(void)
{
  /** abc is a local variable **/
  int abc = 132;
  ptr = &abc;
  return 0;
}

int func1(void)
{

  /** although scope of abc is over still I can change the value in the address  of abc **/
  *ptr = 200;
  printf("the value of abc=%d\r\n",*ptr);

}

int main(void)
{
   func();
   func1();
   return 0;
}

結果: abc=200の値

簡単に言えば、スコープとは何を意味するのでしょうか? 実行時またはコンパイル時に関係がありますか? ご覧のとおり、実行時に何にでもアクセスできます。ただし、ルールに従わないと、コンパイル エラーが発生します。たとえば、別の関数でのローカル変数の参照。コンパイラは、「変数が定義されていません...」というエラーをスローします。

変数について次のように言えますか?

1) Scope attribute comes under compile time.
2) Lifetime attribute comes under run-time.
3) Visibility attribute comes under compile-time
4

7 に答える 7

8

はい、C のメモリ モデルでは何でも簡単にアクセスできるため、上記のようなことを実際に実行して「興味深い」結果を確認できます。

ただし、ここで行ったことはC 標準で未定義の動作(UB) として指定されています。つまり、文字通り何でも起こり得るということです。それはあなたが期待するものかもしれませんし、そうでないかもしれません。

「ローカル変数」にアクセスしなかったことに注意してください。これは、アクセスを行うまでfuncにすでに返されているため、そのローカル変数の有効期間が切れているためです。アクセスしたのは、「たまたま」興味深い値を持つメモリ領域でした。func1内部から呼び出した場合func、動作は明確に定義されます。

さらにいくつかのメモ:

スコープは間違いなくコンパイル時のみの概念です。名前 (変数、識別子など) のスコープは、その名前がコンパイラによって認識されるプログラム コードのサブセットです。

これは、一般的なケースではスコープに依存しない変数の有効期間とは大きく異なり、2 つを混同することはよくある間違いです。ローカル変数の有効期間とスコープは確かに絡み合っていますが、すべてに当てはまるわけではありません。

于 2013-09-04T11:41:32.067 に答える
1

スコープに関する限り、C が一連のレジスタおよびメモリ操作にコンパイルされていると考えるのが最も簡単です。ブロック、for ループ、if ステートメント、構造体などの構造は、コンパイル以外の意味はありません。プログラマーが正気を保つための抽象化。

例とメモリがここにある限り、それを説明する私の試みです。

誰もが言っているように、標準の未定義のアクションの特定のコンパイラ固有の実装を使用しています。これがどのように機能するかを理解するには、作成しているプログラムがヒープとスタックの 2 つのメモリを持っていると考えることができます。例として、char *foo = malloc(50);メモリをヒープにchar foo[] = "Foo"割り当て、それをスタックに割り当てます。スタックは、あなたが何をしているかを記憶するメモリであり、スタック フレームの長いリストが含まれています。関数呼び出しごとにフレームが追加され、リターンごとにフレームがポップされます。ヒープは別の種類のメモリです。

これを説明するために、次のプログラムがあります。

int *ptr;
int func() {
  int abc = 123;
  ptr = &abc;
  return 0;
}

int func1() {
  int def;
  printf("func1() :: *abc=%i\n", *ptr);
  def = 200;
  return 0;
}

int main() {
  func();
  printf("main() :: *ptr=%i\n", *ptr);
  func1();
  printf("main() :: *ptr=%i\n", *ptr);
}

そして、スタック上で次のことが起こります(-は未定義/未使用のメモリ、>左側はプログラムが現在実行されている場所、Xデータです):

|-----|
|-----|
|-----|

入力するmain()と、スタック フレームがスタックにプッシュされます。

 |-----|
 |-----|
>|XXXXX| <- This is where all memory needed to execute main() is.

次にfunc()、実行に必要なメモリに integer を含む whichを呼び出します123

 |-----|
>|XX123| <- This is the stack frame for func()
 |XXXXX| <- Still the stack frame for main()

func()グローバルポインタ*ptrをスタック上の整数のアドレスに設定します。これは、func()値が返されたとき (CPU サイクルの無駄になるため、メモリがクリアされていないとき) に値が残ることを意味します。

 |-----|
 |--123|
>|XXXXX| <- main()

*ptr次の関数を呼び出すまで、引き続き参照できます

 |-----|
>|XXXXX| <- This is the stack frame for func1()
 |XXXXX|

*ptrランダムな値があるように見えますが、メモリ位置にアクセスして変更することはできます。( func()and func1()each がそのスコープ内でローカル整数を 1 つだけ定義している場合、それも*ptrその整数を指す可能性が非常に高くなりfunc1()ます)

ボーナス

プログラムをテストしていませんが、次のように出力されると思います。

main() :: *ptr=123
func1() :: *ptr=<some random values>
main() :: *ptr=<possibly 200, could be something else>
于 2013-09-04T16:11:54.110 に答える
1

スコープとはどういう意味ですか?

変数のスコープは、変数を参照できるテキストの部分です。ローカル変数にはブロック スコープがあります。これは、宣言のポイントからそれを囲む関数本体の最後まで表示されます。
変数の寿命とは何の関係もありません。変数の寿命を示すのは保存期間です。

実行時またはコンパイル時に関係がありますか?

コンパイル時とリンク時に問題が発生します。プログラムがブロック外のローカル変数にアクセスしようとすると、コンパイラはその宣言されていない変数 (ブロックに対してローカル) に関するエラーを返します。
この例はそれをよりよく説明します:

#include <stdio.h>

void userlocal(void);

int main()
{
    int a= 2;

    printf("local a in outer scope of main is %d\n",a);

    userlocal();

    printf("local a in scope of userlocal is %d\n",b); // This will give error at compile time
    return 0;

}

void userlocal(void)
{
    int b = 20;
    printf("local a in scope of userlocal is %d\n",b);
}

出力:

[Error] 'b' undeclared (first use in this function)  

変数について次のように言えますか?

はい、あなたは言うことができます。

于 2013-09-04T11:43:18.173 に答える
1

理論上は「ただの UB」ですが、実際には実際に失敗することを求めています。の場所abcは(私が知っているすべての実装で)スタックのどこかにあります。最初のブロックを離れて別のブロックに入ったので、別の何かがメモリのその場所を占有する可能性が非常に高くなります。上書きするもの。

于 2013-09-04T11:52:19.990 に答える
0

スコープstorage durationはコンパイル時のプロパティであり、変数の参照が有効な場合、または変数に関連付けられたメモリへのアクセスが有効であることを示すオブジェクトの有効期間とは異なる変数が表示されている場合に対処します。

この場合、自動保存期間がありますabc。これは、その期間がそれが含まれているブロックに対して延長されることを意味しfuncます。結果は信用できません。abc

ドラフト C99 標準セクション6.2.4 オブジェクトのストレージ期間の段落から、さまざまなストレージ期間について説明しています:staticおよびautomatic. static変数の有効期間はプログラムの実行全体であると説明し、段落5で次のように述べています。

可変長配列型を持たないこのようなオブジェクトの場合、その有効期間は、関連付けられているブロックへのエントリから、そのブロックの実行が何らかの方法で終了するまで延長されます。[..]

したがって、自動変数の寿命はそれが含まれているブロックであり、段落2は次のように述べています。

オブジェクトの存続期間は、プログラム実行の中で、そのオブジェクト用にストレージが確保されることが保証されている部分です。オブジェクトは存在し、一定のアドレスを持ち、25)、最後に格納された値をその存続期間を通じて保持します。26)オブジェクトが存続期間外に参照される場合、動作は未定義です。ポインターの値は、それが指すオブジェクトがその寿命の終わりに達すると不確定になります。

したがって、保証された有効期間外のオブジェクトを参照することは、未定義の動作です。

于 2013-09-04T11:45:41.810 に答える
0

C のメモリ モデルがフラットであることは間違いありません。また、任意のメモリ領域にアクセスできます。ptrへのグローバル ポインタを次に示しintます。したがって、整数を格納および取得できるアドレスを指します。undefined behaviourこれは、さまざまな種類のシナリオにつながります。

于 2013-09-04T11:42:00.300 に答える