2

学校の先生は、構造体 foo へのポインターに代入する前に、 NULL(struct foo *)に変換し続けます。例えば:

struct foo {
   // smthg else
   struct foo *ptr;
};

struct foo *bar;
bar = (struct foo*)malloc(sizeof(struct foo));
bar->ptr = (struct foo *) NULL;

私を驚かせたのは、彼がその値が NULL であるかどうかをテストする (リンクされたリストが終了したかどうかを確認する) 唯一の場合、彼は次のことを行うことです。

if (aux->ptr != (struct foo *) NULL) {
   ...
}

エラーなどを防ぐために NULL のサイズを「大きく」するのであれば、その理由を彼に尋ねました。しかし、いいえ、彼は私に言いました(かなり気が進まなかったと思います)、コンパイラによるエラーの可能性を防ぐためでした(wtf?)。それは本当に必要ですか?

編集:

彼が教えている言語は C です。彼はおそらく、C で malloc をキャストする必要がないことを知りません。彼がただ慎重なのか無能なのか知りたい. :P

4

6 に答える 6

7

あなたの質問に答えるには: いいえ、NULL特定のポインター型にキャストする必要はありません。コンパイラは特別なケースを作成し、NULLポインター型変換の警告なしで任意のポインター型に割り当てることを許可します。

同様に、 と比較する場合もキャストする必要はありませんNULL

if (aux->ptr != NULL) {
于 2012-05-09T05:31:58.360 に答える
4

の正しい形

struct foo *bar = (struct foo*)malloc(sizeof(struct foo));

Cでは常に

struct foo *bar = malloc(sizeof *bar);

あなたの教授は間違っていて、おそらく C++ で使用しようとして悪い習慣を身につけたのでしょうmalloc(正当な理由で、一般的に嫌われています)。

于 2012-05-09T05:51:36.733 に答える
2

#define NULL 0(C89) C 標準で要求されるように、0 は null ポインター定数ではありませんでした。最近では、そのようなコンパイラに出くわす可能性はほとんどありません。

以前は、NULL をヌル ポインター定数にする必要があるなどのコンテキストで重要execl("cmd", "arg0", "arg1", NULL);でしたが、最近では NULL はヌル ポインター定数であるため、キャストは実際には必要ありません。割り当て操作の場合0、キャスト NULL の代わりに書き込むことができます。このexecl()例では、0 だけを書くことはできません。これintは null ポインター定数である必要はありません。

于 2012-05-09T06:02:33.287 に答える
1

C では、の結果をmalloc変数型にキャストする必要はありません。void *そうしないと、コンパイル時にエラーが発生します (暗黙的に に変換できませんyour_class *)。

教師が適切なコーディングの原則を教えようとしている場合は、キャストが必要です。先生が C++ の準備として C を教えようとしている場合は、キャストの使い方を学ぶ必要があります。そして、教師が「コンパイラによるエラーの可能性を防ぐために」と言っていることに「wtf」は何もありません。おそらく、彼のアドバイスをもっと頻繁に受ける必要があります。教授が無知であると仮定することは、おそらく適切ではありません。

于 2012-05-09T05:28:01.610 に答える
1

NULL は 0 として #defined であるため、NULL を特定のポインター型にキャストする必要はありません。私が考えることができる唯一の理由は、プログラムを作成するときにオブジェクトとポインターの型を覚えておくとよいという意味で教育的なものです。 .

C++ では、初期化に nullptr を使用し、g++ -std=c++0x でコンパイルします。

最後に、C ではなく C++ で malloc の戻り値をキャストする必要があります。ただし、C++ では「new」を使用する必要があります。

于 2012-05-09T05:38:13.843 に答える
-2

この質問に対する正解は、あなたの先生は間違っていないし、無知でもないということです。彼/彼女はあなたに良い習慣を教えているだけです。明示的なキャストを使用することは必須ではありませんが、使用すべき理由が少なくとも 2 つあります。

  1. コードの移植性

    明示的なキャストを使用すると、ANSI C コンパイラ、ANSI 以前のコンパイラ、および最も重要な非 ANSI C 準拠のコンパイラ間でコードを確実に移植できます。教師のコードは、準拠または非準拠、過去、現在、または将来のコンパイラでエラーまたは警告を生成してはなりません。

    ANSI C より前のプラットフォームまたは ANSI に準拠していないプラットフォームでコンパイルする場合は、次のコードを記述します。

    pMyObject = NULL;
    

    一部のシステムでは、次の行に沿ってコンパイラ警告が生成される可能性があります。

    警告: 'void*' から 'struct foo*' への '=' 変換
    警告: 'int' から 'struct foo*' への '=' 変換
    

    コンパイラの警告の目的は、潜在的な問題を警告することです。したがって、警告が明示的なキャストで修正されない限り、警告が 1 つでもコンパイルされるコードは製品品質のコードと見なされるべきではありません。

  2. コードの可読性

    明示的なキャストを使用すると、読みやすさが大幅に向上します。たとえば、 Microsoft Windows SDKに基づく次の実際の例を取り上げます。

    hMyWindow = CreateWindow(NULL, NULL, WM_OVERLAPPED, 0, 0, 100, 100, NULL, NULL, NULL, NULL);
    if (hMyWindow == NULL)
        ...
    

    Microsoft Windows SDK を参照しない限り、この関数に渡されるパラメーターを理解できないことは明らかです。ただし、次のように記述します。

    hMyWindow = CreateWindow((LPCTSTR) NULL, (LPCTSTR) NULL, WM_OVERLAPPED, 0, 0, 100, 100, (HWND) NULL, (HMENU) NULL, (HINSTANCE) NULL, (LPVOID) NULL);
    if (hMyWindow == (HWND) NULL)
        ...
    

    1) 変数の型、2hWindow ) の戻り値の型CreateWindow()、3) すべての関数パラメータの型。このコードを理解するために知っておく必要がある事実上すべての情報があり、現在のファイルをスキャンしたり、別のヘッダー ファイルを探したり、API ドキュメントを探してインターネットを閲覧する時間を無駄にしたりする必要はありません。これにより、コードが自己文書化されます。これは、組み込みのコード参照サポートを持たない多くの非グラフィカル環境の 1 つである場合に特に重要です。

ANSI C99 (ISO/IEC 9899:1999、セクション 6.5.16.1) では、ANSI は NULL ポインター定数 の概念に同意し型付きオブジェクトのポインターへの NULL ポインター定数の代入は正当であることに同意しました。

しかし、先生があなたに上記の方法を教えた本当の理由は、先生が他の良い先生と同じように、現実の世界に向けてあなたを準備しているだけであり、現実の世界では ANSI C 規格は法律ではないからです。従う必要はなく、ほとんどの場合、従いません。コンパイラー企業は、金銭的利益や市場シェアを獲得する必要がある場合、標準を無視または拡張します。さらに、非標準のハードウェアをサポートする必要があるため、非 ANSI C 準拠のコンパイラがインストールされ、C プログラムのコンパイルに使用されている、世界最大のメーカーによる独自のコンピュータ システムが多数存在します。

これが、関連するポインター操作を行うときに明示的なキャストを使用することNULLが非常に良い習慣である理由です。これにより、コードがすぐに理解できるようになり、クリーンにコンパイルされ、後で遭遇する多種多様なプラットフォームやコンパイラ ツールで期待どおりに動作することが保証されます。

于 2012-05-09T09:58:04.613 に答える