2

次の2つのアプローチのいずれかに他のアプローチよりも利点がありますか?

ここでは、最初にテストされ、fopen成功するかどうか、次にすべての変数宣言が行われるかどうかがテストされ、実行される必要がないため、実行されないことが確認されます。

void func(void) {
    FILE *fd;

    if ((fd = fopen("blafoo", "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    int a, b, c;
    float d, e, f;
    /* variable declarations */

    /* remaining code */
}

これは正反対です。fopen失敗した場合でも、すべての変数宣言が行われます

void func(void) {
    FILE *fd;
    int a, b, c;
    float d, e, f;
    /* variable declarations */

    if ((fd = fopen("blafoo", "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    /* remaining code */        
}

2番目のアプローチは、失敗したときに追加のコストを生み出しますか?fopenあなたの考えを聞いてみたいです!

4

5 に答える 5

4

いいえ、費用はかかりません。どちらの例も、同じ結果のバイナリにコンパイルされる可能性があります。代入なしの変数宣言は実際にはCでも行わないため、コードは生成されません。これらの変数に使用できるスペースは、必要に応じてスタックポインターによってスキップされます。

于 2010-06-13T11:49:54.390 に答える
1

失敗するfopenと、アプリケーションは終了するため、変数が初期化されたかどうかは誰も気にしません。アプリケーションはすでに終了しており、静的に割り当てられたメモリはすでに解放されているため、コストはかかりません。前述のように、メモリは割り当てられていませんが、すべてを0などのデフォルト値に設定している場合は割り当てられます。この動作を変更しても、追加のコストは発生しません。

また、2番目のコードはC89に準拠しているため、おそらく望ましいでしょう。

于 2010-06-13T11:49:19.377 に答える
1

同じスコープ内の関数内のすべての変数に対するスタック変数の割り当ては、どちらの場合も関数の先頭で行われる可能性が高いため、どちらの方法でも問題ありません。

于 2010-06-13T11:59:13.450 に答える
1

あなたの例の変数宣言は、ほとんどのコンパイラで余分なコストはかかりません。それらが発生する可能性があるのは、重要なコードを生成する必要のある初期化値がある場合のみです。

例えば:

void func(const char * filename) {
    FILE *fd;
    int a, b, c;
    size_t z = strlen(filename);
    float d, e, f;
    /* variable declarations */

    if ((fd = fopen(filename, "+r")) == NULL ) {
          fprintf(stderr, "fopen() failed\n");
          exit(EXIT_FAILURE);
    }

    /* remaining code */    
    /* Some code that uses z */
}

この例strlenでは、ファイルを開こうとする前に呼び出すことができますが、その値は使用されません。strlenの後に呼び出しを配置すると、fopenコードが改善される可能性があります。strlenコンパイラは、のようないくつかの関数が純粋に機能的であり(副作用がなく、引数を使用して結果を生成するだけである)、呼び出しをそれ自体strlenの下に移動できることを知っていることが多いため、これは実際には最良の例ではありませんがfopen、アイデアを得る必要があります。

于 2010-06-13T14:49:52.293 に答える
0

違いはありませんが、2つのバージョンのアセンブリ出力をいつでも比較して確認できます。

スタック上のスペースは、おそらくコンパイラー/コンパイラーライターのベースポインター+オフセットに変数名をマッピングする優れた関数を取得するために、常に関数エントリで準備されます。初期化に関しても、違いはありません。両方のバージョンの変数に何かが書き込まれるまで、内容は未定義です。

ただし、C ++では、初期化をジャンプするときに問題が発生する可能性があります(この例のコードでは実行していません)が、C++の推論ははるかに複雑です。

于 2010-06-13T12:08:41.353 に答える