私はいつも単純if(p != NULL){..}
に仕事をすると思っています。しかし、この Stack Overflow questionを読んだ後では、そうではないようです。
では、 NULL ポインターはゼロ以外の値を持つことができるという質問のすべての議論を吸収した後、NULL ポインターをチェックする標準的な方法は何ですか?
私はいつも単純if(p != NULL){..}
に仕事をすると思っています。しかし、この Stack Overflow questionを読んだ後では、そうではないようです。
では、 NULL ポインターはゼロ以外の値を持つことができるという質問のすべての議論を吸収した後、NULL ポインターをチェックする標準的な方法は何ですか?
私はいつも単純にif(p!= NULL){..}がその仕事をするだろうと思っています。
そうなる。
まず、100% 明確にするために、ここでは C と C++ の間に違いはありません。次に、あなたが引用したスタック オーバーフローの質問では、ヌル ポインターについて言及していません。無効なポインターが導入されます。少なくとも標準に関する限り、それらを比較しようとするだけで未定義の動作を引き起こすポインター。一般に、ポインターが有効かどうかをテストする方法はありません。
最後に、null ポインターをチェックする方法は 3 つあります。
if ( p != NULL ) ...
if ( p != 0 ) ...
if ( p ) ...
マシン上の null ポインターの表現に関係なく、すべて機能します。そして、すべてが何らかの形で誤解を招くものです。どちらを選択するかは、最も悪いものを選択する問題です。正式には、最初の 2 つはコンパイラにとって同一です。定数NULL
or0
は の型の null ポインタに変換されp
、変換の結果は と比較され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 互換ではありません:-)。
コンパイラは一貫した型システムを提供し、一連の標準変換を提供する必要があります。整数値 0 も NULL ポインターもすべてゼロのビットで表す必要はありませんが、コンパイラーは、入力ファイル内の「0」トークンを整数ゼロの正しい表現に変換し、ポインター型にキャストする必要があります。整数からポインター表現に変換する必要があります。
これが意味することは、
void *p;
memset(&p, 0, sizeof p);
if(p) { ... }
ここでビットパターンについて仮定しているため、すべてのターゲットシステムで同じように動作することは保証されていません。
例として、私はメモリ保護を持たず、割り込みベクトルをアドレス 0 に保持する組み込みプラットフォームを使用しているため、慣例により、整数とポインタは変換時に 0x2000000 と XOR され、(void *)0 はそのアドレスを指すままになります。逆参照するとバス エラーが発生しますが、ステートメントでポインターをテストすると、if
まず整数表現に戻り、次にすべてゼロになります。
nullポインタの実際の表現は、ここでは関係ありません。値がゼロの整数リテラル(0
およびの有効な定義を含むNULL
)は、実際の表現に関係なく、nullポインターを与える任意のポインター型に変換できます。したがって、、p != NULL
およびp != 0
はp
すべてnull以外のポインタの有効なテストです。
のようにねじれたものを書いた場合、nullポインタのゼロ以外の表現で問題が発生する可能性があるp != reinterpret_cast<void*>(0)
ので、そうしないでください。
あなたの質問にはC++だけでなくCのタグも付いていることに気づきました。私の答えはC++に関するものであり、他の言語は異なる場合があります。どの言語を使用していますか?
どうやらあなたが参照しているスレッドは約C++
です。
C
スニペットでは常に機能します。シンプルなものが好きif (p) { /* ... */ }
です。
C でのすべての比較は表現ではなく値として行われるため、ポインターの表現は比較とは無関係です。表現を比較する唯一の方法は、次のような恐ろしいものです。
static const char ptr_rep[sizeof ptr] = { 0 };
if (!memcmp(&ptr, ptr_rep, sizeof ptr)) ...