0

私がオフィスで最近参加したコーディング スタイルのプレゼンテーションでは、変数を定義するときに変数を (既定値に) 割り当てるべきではないと主張していました。代わりに、使用する直前にデフォルト値を割り当てる必要があります。だから、次のようなもの

int a = 0;

眉をひそめるべきです。

明らかに、「int」の例は単純化されていますが、ポインターなどの他の型についても同じことが言えます。

さらに、C99 互換コンパイラが上記のケースで警告を出すようになったことも言及されました。

上記のアプローチは、構造体に対してのみ有用に見えます。つまり、使用前にのみ memset します。これは、構造体がエラー レッグでのみ使用される (または埋められる) 場合に効率的です。

他のすべてのケースでは、コードの作成中および保守中に初期化されていないポインターが原因で多くのバグに遭遇したため、デフォルト値を定義して割り当てることは賢明な方法であることがわかりました。さらに、コンストラクターを介した C++ も同じアプローチ、つまり定義と代入を提唱していると思います。

なぜ(もし)C99標準が定義と割り当てを好まないのか疑問に思っています。コーディング スタイルのプレゼンテーションで推奨されていることを実行する上で、それらはかなりのメリットがありますか?

4

5 に答える 5

1

通常、値がわかっている場合は変数を定義するときに変数を初期化し、値が不明な場合は変数を初期化しないことをお勧めします。いずれにせよ、スコープ ルールが許す限り、できるだけ近くに配置してください。

代わりに、使用する直前にデフォルト値を割り当てる必要があります。

通常、デフォルト値はまったく使用しないでください。C99 では、コードと宣言を混在させることができるため、値を代入する前に変数を定義しても意味がありません。取るべき値がわかっている場合は、デフォルト値を設定しても意味がありません。

さらに、C99 互換コンパイラが上記のケースで警告を出すようになったことも言及されました。

あなたが示したケースではありません - あなたは持っているという警告を受けませんint x = 0;。誰かがこれを混同したのではないかと強く疑っています。値を代入せずに変数を使用すると、コンパイラは警告を発します。

... some code ...

int x;

if ( a )
    x = 1;
else if ( b )
    x = 2;
// oops, forgot the last case else x = 3;

return x * y;

その場合、少なくとも gcc では x が初期化されずに使用される可能性があるという警告が表示されます。

xの前に値を割り当てても警告は表示されませんがif、割り当てが初期化子として行われるか、別のステートメントとして行われるかは関係ありません。

2 つのブランチに値を 2 回割り当てる特別な理由がない限り、最初にデフォルト値を x に割り当てても意味がありません。これにより、すべてのブランチをカバーしたというコンパイラの警告が停止するためです。

于 2009-06-19T14:07:26.770 に答える
1

C99にはそのような要件 (または私が知っているガイドライン) はなく、コンパイラはそれについて警告しません。それは単にスタイルの問題です。

コーディング スタイルに関する限り、物事を文字通りに捉えすぎたと思います。たとえば、次の場合、あなたのステートメントは正しいです...

int i = 0;

for (; i < n; i++)
        do_something(i);

...または...

int i = 1;

[some code follows here]

while (i < a)
        do_something(i);

...しかし、私の考えでは、早期の「宣言と割り当て」でより適切に処理される他のケースがあります。次のように、スタック上に構築された構造体またはさまざまな OOP 構造体を検討してください。

struct foo {
        int bar;

        void *private;
};

int my_callback(struct foo *foo)
{
        struct my_struct *my_struct = foo->private;

        [do something with my_struct]

        return 0;
}

または(C99構造体初期化子)のように:

void do_something(int a, int b, int c)
{
        struct foo foo = {
                .a        = a,
                .b        = b + 1,
                .c        = c / 2,
        };

        write_foo(&foo);
}
于 2009-06-11T06:25:07.763 に答える
0

初期化されていないポインターが原因のバグが非常に多いため、各変数を NULL_PTR で宣言し、各プリミティブを無効/デフォルト値で宣言することを常に推奨していました。

私は RTOS と高性能だがリソースの少ないシステムに取り組んでいるため、使用するコンパイラが初期化されていない使用法を検出できない可能性があります。最新のコンパイラも 100% 信頼できるとは思えませんが。

マクロが広く使用されている大規模なプロジェクトでは、Kloclwork /Purify でさえ初期化されていない使用法を見つけることができないというまれなシナリオを見てきました。

だから私は、あなたが普通の古い C/C++ を使っている限り、それを使い続けると言います。

.Net などの最新の言語は、変数の初期化を保証するか、初期化されていない変数の使用に対してコンパイラ エラーを発生させることができます。次のリンクは、パフォーマンス分析を行い、.NET で 10 ~ 20% のパフォーマンス ヒットがあることを検証します。分析はかなり詳細で、よく説明されています。

http://www.codeproject.com/KB/dotnet/DontInitializeVariables.aspx

于 2009-06-11T06:58:06.057 に答える
0

標準がそれについて何か言っているかどうかは完全には確信が持てませんが、私はアドバイスにある程度同意します.

問題は、最新のコンパイラが初期化されていない変数の使用を検出できることです。初期化時に変数をデフォルト値に設定すると、その検出が失われます。また、デフォルト値もバグを引き起こす可能性があります。確かにあなたの例の場合、int a = 0;. 0の適切な値は誰だとa思いますか?

1990 年代であれば、このアドバイスは間違っていたでしょう。今時、それは正しい。

于 2009-06-11T05:34:55.397 に答える
0

コードで (できるだけ多くの) null チェックを行う必要がないように、いくつかのデフォルト データを変数に事前に割り当てておくと非常に便利です。

于 2009-06-11T05:35:23.197 に答える