web-dev-qa-db-ja.com

ポインターがNULLポインターであるかどうかを確認するにはどうすればよいですか?

私はいつもif(p != NULL){..}が仕事をするだろうといつも思っています。しかし このStack Overflowの質問 を読んだ後は、そうではないようです。

では、NULLポインターはゼロ以外の値を持つことができるという質問のすべての議論を吸収した後、NULLポインターをチェックする標準的な方法は何ですか?

41
cpuer

私はいつも単純にif(p!= NULL){..}が仕事をすると考えています。

そうなる。

52
cnicutar

まず、100%明確にするために、CとC++にはnoの違いがあります。 2番目に、引用したStack Overflowの質問では、nullポインターについては説明していません。無効なポインターが導入されます。少なくとも標準に関する限り、それらを比較しようとするだけで未定義の動作を引き起こすポインター。一般に、ポインターが有効かどうかをテストする方法はありません。

最後に、nullポインターをチェックする3つの広範な方法があります。

_if ( p != NULL ) ...

if ( p != 0 ) ...

if ( p ) ...
_

マシン上のNULLポインターの表現に関係なく、すべて機能します。そして、すべてが何らかの形で誤解を招きます。どれを選ぶかは、最も悪いものを選ぶことの問題です。正式には、最初の2つはコンパイラーと同じです。定数NULLまたは_0_はp型のNULLポインターに変換され、変換結果はpと比較されます。 NULLポインターの表現に関係なく。

3番目はわずかに異なります:pは暗黙的にboolに変換されます。ただし、暗黙的な変換は_p != 0_の結果として定義されるため、同じ結果になります。 (これは、3番目のスタイルを使用するための有効な引数が実際にないことを意味します。オフセットメリットなしで、暗黙の変換で難読化されます。)

最初の2つのうちどちらを好むかは主にスタイルの問題であり、おそらく他の場所のプログラミングスタイルによって部分的に決定されます。関係するイディオムによっては、うその1つが他よりも厄介になります。それが比較の質問である場合、ほとんどの人はNULLを好むと思いますが、f( NULL )のようなものでは、選択されるオーバーロードはf( int )であり、ポインターによるオーバーロードではありません。同様に、fが関数テンプレートの場合、f( NULL )intにテンプレートをインスタンス化します。 (もちろん、g ++などの一部のコンパイラは、NULLが非ポインターコンテキストで使用されると警告を生成します。g++を使用する場合は、NULLを使用する必要があります。)

C++ 11 では、もちろん、推奨されるイディオムは次のとおりです。

_if ( p != nullptr ) ...
_

、他のソリューションのほとんどの問題を回避します。 (ただし、C互換ではありません:-)。)

29
James Kanze

コンパイラは、一貫した型システムを提供し、一連の標準変換を提供する必要があります。整数値0もNULLポインターもすべてゼロのビットで表す必要はありませんが、コンパイラーは入力ファイルの「0」トークンを整数ゼロの正しい表現に変換し、ポインター型にキャストする必要があります。整数からポインター表現に変換する必要があります。

これが意味するのは

void *p;
memset(&p, 0, sizeof p);
if(p) { ... }

ここでビットパターンについて仮定しているため、すべてのターゲットシステムで同じ動作をすることは保証されていません。

例として、メモリ保護がなく、割り込みベクトルをアドレス0に保持する組み込みプラットフォームがあるため、慣例により、整数とポインターは変換時に0x2000000とXORされ、(void *)0はアドレスを指します参照解除時にバスエラーが生成されますが、ifステートメントでポインターをテストすると、最初に整数表現に戻り、次にすべてゼロになります。

9
Simon Richter

ここでは、nullポインターの実際の表現は関係ありません。値がゼロの整数リテラル(_0_およびNULLの有効な定義を含む)は、実際の表現が何であれ、nullポインターを与える任意のポインター型に変換できます。したがって、_p != NULL_、_p != 0_、およびpはすべて、非NULLポインターの有効なテストです。

p != reinterpret_cast<void*>(0)のようなねじれたものを書いた場合、nullポインターのゼロ以外の表現で問題が発生する可能性があるため、そうしないでください。

私はあなたの質問がC++と同様にCとタグ付けされていることに気付いたばかりです。私の答えはC++についてですが、他の言語は異なる場合があります。どの言語を使用していますか?

6
Mike Seymour

どうやらあなたが参照するスレッドは_C++_についてです。

Cでは、スニペットは常に機能します。単純なif (p) { /* ... */ }が好きです。

4
pmg

Cでのすべての比較はvalues表現ではなく行われるため、ポインターの表現はそれらの比較とは無関係です。表現を比較する唯一の方法は、次のような恐ろしいものです。

static const char ptr_rep[sizeof ptr] = { 0 };
if (!memcmp(&ptr, ptr_rep, sizeof ptr)) ...
2
R..

さて、この質問は2011年にさかのぼって回答されましたが、nullptrin C++ 11 があります。私が現在使用しているのはそれだけです。

Stack Overflowの詳細この記事 を読むことができます。

1
JohnJohn