モバイル セキュリティの面接での質問 - プログラミングの基礎

静的関数、ローカル変数、およびグローバル変数のどのセグメントに、特殊な場合にすべてのローカル変数をスタックに配置する必要があるか

static 関数
C 言語では、static キーワードを使用して関数と変数を修飾できます。ここでは主に静的に変更された関数の場合について説明します。
静的関数 (static 関数) は、それが定義されているソース ファイル内でのみ使用でき、動作範囲は現在のソース ファイルに限定されます。これにより、名前の競合が回避され、コードの保守性が向上します。他のソース ファイルでは、静的関数に関数名でアクセスすることはできません。
ローカル変数とグローバル変数がどのセグメントに配置されるか
C 言語では、プログラムのメモリ レイアウトは通常、次のセグメントに分割されます。

  1. コードセグメント(Code Segment):プログラムのコードを格納します。
  2. データセグメント (Data Segment): 初期化されたグローバル変数と静的変数を格納します。
  3. BSS セグメント (シンボルによって開始されるブロック): 初期化されていないグローバル変数と静的変数を格納します。
  4. ヒープ (Heap): 動的メモリ割り当てに使用されます。
  5. スタック (スタック): ローカル変数および関数呼び出しのコンテキスト情報を保存するために使用されます。

これらのメモリ セグメントの定義に従って、ローカル変数は通常スタックに格納され、グローバル変数は初期化されているかどうかに応じてデータ セグメントまたは BSS セグメントに格納されます。
ローカル変数はスタックに配置する必要がありますか?
ほとんどの場合、ローカル変数はスタックに配置されます。ただし、特殊な場合には、ローカル変数がスタックに割り当てられない場合があります。典型的な例は、C11 標準の _Thread_local ストレージ クラス修飾子を使用して宣言されたローカル変数です。このような変数には各スレッドに独立した記憶領域があるため、通常はスタックに割り当てられません。例えば:

void some_function() {
    
    
    _Thread_local int local_var; // 这个局部变量不会分配在栈上
}

これに加えて、コンパイラの最適化はローカル変数の格納場所にも影響を与える可能性があります。たとえば、コンパイラは、一部のローカル変数をスタックに割り当てる代わりにレジスタに入れる場合があります。この状況は、コンパイラーの実装と最適化オプションによって異なります。

C++ メモリ オブジェクト レイアウト (関数、仮想関数、純粋仮想関数)、メンバー関数の呼び出しアドレスは何ですか?

  • 通常のメンバー関数はオブジェクトのメモリを占有せず、コード セグメントに格納されます。通常のメンバー関数を呼び出す場合、コンパイラはコンパイル時に呼び出し先のアドレスを決定します。
  • クラスに仮想関数が含まれる場合、オブジェクトのメモリ レイアウトには、仮想関数テーブル (vtable) を指す仮想関数テーブル ポインター (vptr) が含まれます。仮想関数テーブルは、仮想関数のアドレスを格納する関数ポインターの配列です。仮想関数を呼び出す場合、関数アドレスは仮想関数テーブル ポインターによって決定されます。
  • 純粋な仮想関数は実装されていないため、仮想関数テーブル内のその位置は 0 で埋められます。派生クラスはこの純粋仮想関数を実装する必要があります。実装しないと、クラスも抽象クラスになり、インスタンス化できなくなります。

JavaスタックとCスタックの違い

  • Java スタックは Java 仮想マシン (JVM) の一部であり、ローカル変数や Java メソッド呼び出しのオペランド スタックなどの情報を格納するために使用されます。C スタックはオペレーティング システムによって管理されるメモリ領域であり、ローカル変数と C/C++ 関数呼び出しの呼び出し情報を格納するために使用されます。
  • Java スタックは自動メモリ管理 (ガベージ コレクションなど) をサポートしますが、C スタックではプログラマが手動でメモリを管理する必要があるため、メモリ リークやスタック オーバーフローなどの問題が発生しやすくなります。
  • Java スタックのデータ型は JVM 仕様によって制限されますが、C スタックは柔軟性が高く、さまざまなデータ型と構造を格納できます。

. Java と C++ のオブジェクト指向の違いは何ですか?

  • 継承: Java は単一継承をサポートし、クラスは 1 つの親クラスのみを継承できます。C++ は多重継承をサポートし、クラスは複数の親クラスを継承できます。
  • 抽象クラスとインターフェイス: Java では、抽象クラスには抽象メソッドと具象メソッドを含めることができ、インターフェイスには抽象メソッドのみを含めることができます。C++ では、抽象クラスのみが存在し、インターフェイスの概念はありません。
  • アクセス制御: Java は、パブリック、プロテクト、プライベート、およびデフォルト (パッケージ アクセス) の 4 つのアクセス制御文字をサポートします。C++ は、パブリック、プロテクト、プライベートの 3 つのアクセス制御文字をサポートします。
  • メモリ管理: Java は自動メモリ管理 (ガベージ コレクション) をサポートしていますが、C++ ではプログラマが新規/削除操作を含むメモリを手動で管理する必要があります。
  • ポインタ: Java はポインタを直接サポートしておらず、参照型変数は実際にはオブジェクトへの参照です。C++ はポインタと参照をサポートし、より低レベルの操作機能を提供します。

ヒープとスタックの違いは?

  • 管理方法: ヒープは動的に割り当てられるメモリ領域であり、プログラマは手動でメモリを適用および解放する必要があります。スタックは、自動的に割り当ておよび再利用されるメモリ領域であり、オペレーティング システムまたはプログラミング言語のランタイム環境によって管理されます。
  • ストレージの内容: ヒープは主に動的に割り当てられたオブジェクトとデータを保存するために使用され、スタックは主にローカル変数と関数呼び出しの呼び出し情報を保存するために使用されます。
  • ライフサイクル: ヒープ内のデータのライフサイクルはプログラマによって制御され、複数の関数呼び出しにまたがることができます。スタック内のデータのライフサイクルは関数呼び出しで開始および終了し、関数が返されるとローカル変数は破棄されます。
  • アクセス速度: スタックのアクセス速度は、通常、ヒープよりも高速です。これは、スタックには固定のアクセス順序 (後入れ先出し、LIFO) があり、CPU レジスタによってスタックの先頭が示され、メモリヒープへのアクセスには、より複雑なメモリ管理操作が含まれる場合があります。
  • メモリ空間: ヒープは動的に割り当てられたオブジェクトを格納するために使用され、より多くのメモリを必要とする場合があるため、通常、ヒープのメモリ空間はスタックのメモリ空間よりも大きくなります。スタックのメモリ空間は、格納するためにのみ使用されるため比較的小さいです。関数呼び出しの一時データ。
  • 断片化の問題: ヒープでは、ヒープ メモリの割り当てと解放が不連続であるため、メモリの断片化が発生しやすくなりますが、スタックでは、スタック メモリの割り当てと解放が連続しているため、メモリの断片化が発生しにくくなります。

おすすめ

転載: blog.csdn.net/u010671061/article/details/132289575