メインコンテンツ

最小スタック使用量

入れ子にされたスコープを考慮した関数内のローカル変数の合計サイズに呼び出し先の最大スタック使用量を加えたもの

説明

このメトリクスは Code Prover 解析のみで報告されます。

このメトリクスでは、関数によるスタック使用量の楽観的な推定値が提供されます。メトリクス最大スタック使用量とは異なり、このメトリクスでは入れ子にされたスコープを考慮します。たとえば、変数が条件付きステートメントの相互に排他的な 2 つの分岐で定義されている場合、メトリクスでは、一方の分岐の変数に割り当てられたスタック領域はもう一方の分岐で再利用できると見なします。

メトリクスは、以下のサイズのバイト単位の合計です。

  • ローカル変数サイズのより低い推定値.

  • 関数呼び出し先のスタック使用量の最大値。計算では、各呼び出し先の最小スタック使用量を使用します。

    たとえば、この例では、func の最小スタック使用量は func1 または func2 の最小スタック使用量のうちの "小さい方" と同じです。

    void func(void) {
        func1();
        func2();
    }

    関数呼び出しが条件付きステートメントの複数の分岐にある場合、このメトリクスではスタック使用量の最も小さい分岐が考慮されます。

    解析では、どの関数呼び出しが実際に発生するかを解決したら、後からスタック サイズの推定を行います。たとえば、関数呼び出しが到達不能コードで発生する場合、スタック サイズにはその呼び出しは考慮されません。解析では、関数ポインターによる呼び出しを考慮することもできます。

実際のスタック使用量は、このメトリクス値と異なる可能性があります。

  • 一部の変数はスタックではなくレジスタに保存されます。

  • コンパイラでは、メモリの一定の最適化を有効にするために、変数存続の解析が実行されます。このメトリクスを推定する際、Polyspace® ではこれらの最適化が考慮されません。

  • コンパイラでは、関数呼び出し中に追加メモリが使用されます。たとえば、コンパイラは実行で次の関数呼び出しが返る先のアドレスを保存します。このメトリクスを推定する際、Polyspace ではこの隠れたメモリの使用は考慮されません。

  • コンパイラはいくつかの方法で一時変数を最適化します。このメトリクスでは、一時変数が除外されます。ユーザーによって明示的に宣言されている変数のみが考慮されます。

ただし、このメトリクスではスタック使用量の妥当な推定値が提供されます。

基本型のサイズを判断するため、本ソフトウェアではターゲット プロセッサ タイプ (-target)の仕様が使用されます。メトリクスでは、コード内の #pragma pack 命令が考慮されます。

すべて展開する

double func2(int);


double func(int status) {
    double res = func2(status);
    return res;
}


double func2(int status) {
    double res;
    if(status == 0) {
      int temp;    
      res = 0.0;
    }
   else {
      double temp;
      res = 1.0;
    }
   return res;
}

この例では、int を 4 バイト、double を 8 バイトと仮定して、最小スタック使用量は次のようになります。

  • func2:28 バイト

    この値には、パラメーター (4 バイト)、ローカル変数 res (8 バイト)、2 つのローカル変数 temp のうち 1 つ (8 バイト)、および戻り値 (8 バイト) のサイズが含まれます。

    メトリクスでは、2 番目の temp が定義される場合、1 番目の temp は存在しないことを考慮します。データ型が double の変数 temp の方がサイズが大きいため、これを使用します。

  • func:48 バイト

    この値には、パラメーター、ローカル変数 res、および戻り値のサイズの合計 20 バイトが含まれます。この値には、呼び出し先の func2 の最小スタック使用量である 28 バイトが含まれます。

void func1(int);
void func2(void);



void func(int status) {
    func1(status);
    func2();
}


void func1(int status) {
    if(status == 0) {
      int val;
    }
    else {
      double val2;
    }
}


void func2(void) {
    double val;
}

この例では、int を 4 バイト、double を 8 バイトと仮定して、最小スタック使用量は次のようになります。

  • func1:12 バイト

    この値にはパラメーター (4 バイト) のサイズと、2 つのローカル変数のうちの大きいほうの変数として、この場合は val2 (8 バイト) のサイズが含まれます。

  • func2:8 バイト

  • func:16 バイト

    この値には、パラメーター (4 バイト) および func1func2 の最大スタック使用量 (12 バイト) のサイズが含まれます。

void func1(void);
void func2(void);



void func(int status) {
    if(status==0)
        func1();
    else
        func2();
}


void func1(void) {
    double val;
}


void func2(void) {
    int val;
}

この例では、int を 4 バイト、double を 8 バイトと仮定して、最小スタック使用量は次のようになります。

  • func1:8 バイト

  • func2:4 バイト

  • func:8 バイト

    この値には、パラメーター (4 バイト) および 2 つの分岐の最小スタック使用量 (4 バイト) のサイズが含まれます。

#include <stdarg.h>


void fun_vararg(int x, ...) {
  va_list ap;
  va_start(ap, x);
  int i;
  for (i=0; i<x; i++) {
    int j = va_arg(ap, int);
  }
  va_end(ap);
}



void call_fun_vararg1(void) {
  long long int l = 0;
  fun_vararg(3, 4, 5, 6, l);
}



void call_fun_vararg2(void) {
  fun_vararg(1,0);
}

この関数で、fun_vararg は可変個のパラメーターをもつ関数です。fun_vararg の最小スタック使用量では、最小個数の引数での fun_vararg の呼び出しが考慮されます。最小個数の引数での呼び出しは、2 つの引数 (固定パラメーターに 1 つ、可変パラメーターに 1 つ) がある call_fun_vararg2 での呼び出しです。最小スタック使用量は次のようになります。

  • fun_vararg:20 バイト。

    この値では以下を考慮しています。

    • 固定パラメーター x のサイズ (4 バイト)。

    • 最小個数のパラメーターで呼び出す場合の可変パラメーターのサイズ。その呼び出しには int 型の可変引数が 1 つだけあります (4 バイト)。

    • ローカル変数 ij、および ap のサイズ (12 バイト)。va_list 変数のサイズでは、ターゲットで定義されるポインター サイズが使用されます (この場合、4 バイト)。

  • call_fun_vararg1:44 バイト。

    この値では以下を考慮しています。

    • 5 つの引数がある fun_vararg のスタック サイズ使用量 (36 バイト。このうち、12 バイトはローカル変数サイズ分で、20 バイトは fun_vararg の固定および可変パラメーター分)。

    • ローカル変数 l のサイズ (8 バイト)。

  • call_fun_vararg2:20 バイト。

    call_fun_vararg2 にはローカル変数がないため、この値は、2 つの引数がある fun_vararg のスタック サイズ使用量と同じです (20 バイト)。

メトリクス情報

グループ: 関数
頭字語: MIN_STACK
HIS メトリクス:いいえ

バージョン履歴

R2017b で導入

すべて展開する