ヌルポインタ

ヌルポインタ（ ）とは、何のオブジェクトも指していないことを表す特別なポインタの値である。

プログラムではヌルポインタを、不定長のリストの終端を表したり、何らかの動作の結果が失敗であることを表したりするのに使用する。後者の用法は、nullable型やオプション型の Nothing 値（None 値）を使用することもできる。

ヌルポインタの値や型がいかなるものかという詳細は言語によって異なる。実際的にはいかなるオブジェクトも参照しないという言語もあり、参照先を求めようとするとJava（NullPointerException）のように例外が発生するものもある。

ヌルポインタはほとんどの処理系（この場合、言語処理系プログラムだけではなく、ハードウェアまでを含めて）で、内部的に数値0で表現されるが、ごく希に、0でない処理系もある。言語仕様上の意味としては普通「アドレス0（あるいは他のアドレス）を指し示すポインタ」ではなく、どこも指し示さないものとされる。

ヌルポインタを未初期化のポインタと混同してはならない。ヌルポインタは、あらゆる有効なオブジェクトとも異なることが保証されている。それに対し、言語や実装によっては、未初期化のポインタはそのような保証はなく、C言語の自動変数のようにでたらめなアドレス（不定値）を指している可能性もある。

ヌルポインタはヌル値とは意味が違う。ヌルポインタは多くのプログラミング言語において「値がない (no value)」ことを意味し、ヌル値はリレーショナルデータベースにおいて「未詳値 (unknown value)」であることを意味する。ほとんどのプログラミング言語では2つのヌルポインタは等しいが、リレーショナルデータベースエンジンは2つのヌル値を等しいとはみなさない（それらは未詳値を表しているので、それらが等しいかどうかはわからない）。

 C言語 
C言語では、すべての型の2つのヌルポインタは等しいことが保証されているISO/IEC 9899, §6.3.2.3, ¶4: Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.。また、マクロ NULL が処理系定義のヌルポインタ定数 () に展開されるものと規定されているISO/IEC 9899, §7.17, ¶3: NULL... which expands to an implementation-defined null pointer constant...。C89/C90 (ISO/IEC 9899:1990) や C99 (ISO/IEC 9899:1999) では、NULL はヌルポインタ定数を表現するマクロとして定義され、多くの実装においてヌルポインタ定数は整数定数の 0 もしくは 0 を汎用ポインタ void * に型キャストしたものとして定義されているNULL - cppreference.com (C)。C23 (ISO/IEC 9899:2024) ではキーワード nullptr がヌルポインタを表す、左辺値とならない定数値として追加され、その型も nullptr_t として追加される予定である。規格上は、依然としてマクロNULLは処理系定義のヌルポインタ定数に展開されるものであることには変わりないISO/IEC 9899:2024 (en) — N3220 working draft, §7.21, ¶4が、nullptrに展開される実装がありえることになる。

C言語における汎用ポインタ型はあらゆるポインタ型に暗黙的変換可能となっているため、ポインタ型変数にNULLを代入する際は型キャストの記述が不要となる。POSIX.1-2008 では整数定数の 0 ではなく、0 を void * に型キャストした物、(void *) 0 でなければならないと定義していて、rationale にて、整数の 0 ではあってはならないと、その定義の差を明記しているstddef.h - standard type definitions - The Open Group Base Specifications Issue 7。よって、ほぼ全ての標準Cライブラリは NULL を (void *) 0 としている。そして、C89, C99 では、ヌルポインタ定数を、（void * 以外を含めた）ポイント型に型キャストした物をヌルポインタと定義している。ほとんどの実装はそのまま変換するが、C89, C99 の仕様では、整数からポインタ、ポインタから整数への型キャストがどのような結果になるかは実装依存と明記されていて、ポインタに 0 や NULL を代入したときに、ほとんどのコンパイラは数値の 0 を代入したというコンパイル結果を生成するが、数値の 0 以外を代入するというコンパイル結果を生成しても良いという仕様になっているCan a conforming C implementation #define NULL to be something wacky - Stack Overflow。整数の 0 をポインタにキャストするとヌルポインタとなることは規定されているが、ヌルポインタを整数にキャストしても 0 になることは規定されていない。存在するオブジェクトや関数へのポインタはヌルポインタであってはならないと規定されている。はほとんど無いが、歴史的には、ヌルポインタを 0 以外で表現することもあったcomp.lang.c FAQ list - Question 5.17。

ヌルポインタを参照して、そのメモリアドレスに読み書きしようとすると、それは何も指していないため、メモリ保護の仕組みが存在する実行環境では、通常セグメンテーション違反やアクセス違反が発生する。この場合、Unix系ではシグナル、Windowsでは構造化例外処理による例外が生成され、特に対処しなければ当該のプロセスは異常終了（クラッシュ）となる。一方、メモリ保護のない実行環境、例えばx86のリアルモードでは、アドレス0000:0000は読み書きが可能であり、ヌルポインタを参照したメモリアクセスは成功しクラッシュはしないものの、不定の期待しない動作になる。ただし、ヌルポインタへの参照があえて定義されている場合もある。例えば、16ビットのリアルモードx86デバイスのためにCで記述されたBIOSコードは、ヌルポインタを参照することにより、物理アドレス0に(IDT) を書く場合がある。ヌルポインタの参照をしないようにコンパイラが最適化することもできる。それにより、セグメンテーション違反を避けられるが、他の望ましくないふるまいを引き起こす。

 C++ 
C++では、C言語よりも型チェックが厳密になり、汎用ポインタvoid *をあらゆるポインタ型に暗黙的変換することが不可能になった。代わりに、整数リテラル 0 がヌルポインタ定数を意味するという仕様になった。C言語からの移植を容易にするためなどの目的で、NULLマクロ自体は依然として標準ヘッダーで定義され、実装定義のヌルポインタ定数に展開される仕様となっているがISO/IEC 14882:1998, C.2.2.3 Macro NULL、前述の理由からと定義してしまうと、以外のポインタに代入する際は明示的な型キャストが必要になるため、C言語とは異なり整数リテラル0に展開される実装となっていることが多い。Cと共有されるヘッダーでは、通例__cplusplusの定義有無でNULLの定義が切り替わる実装となっている。

ただし、整数リテラル 0 をヌルポインタとみなすという仕様は、関数オーバーロードやテンプレート関連でしばしば問題を引き起こす結果となった。C++11では代替として、std::nullptr_tという型を持ち、明確にヌルポインタであることを表すnullptrリテラルが導入されたnullptr - cpprefjp C++日本語リファレンス。C++11以降でもNULLマクロは引き続き利用可能だが、整数リテラル0に展開される実装とは限らず、nullptrに展開される実装もありえるNULL - cppreference.com (C++)。

 その他の言語 
Pascalでは綴り記号word symbol、すなわち予約語。『PASCAL 原書第4版』§1.2 nil である。nil は、空の値を表す『PASCAL 原書第4版』§8.1。

そのほかにも参照型の概念を持つ言語には、用語やキーワードこそ違えど同様なものが存在する。例えばJavaやC#ではnull、C++/CLIおよびC++11ではnullptr、Visual BasicおよびVisual Basic .NETではNothing、PythonではNone、Objective-CとRubyではnil、REALbasicではNilがヌルポインタに相当するキーワードである。ポインタではなく参照を利用する言語の場合、概念上ヌルポインタに相当するものはヌル参照 () と呼ばれる。

 歴史 

2009年にアントニー・ホーアは、彼が1965年にALGOL Wの一部としてヌル参照を発明したと述べている。2009年のカンファレンスでホーアはこの発明を「10億ドルの誤り」と述べた。

 脚注 

外部リンク
.
 C言語FAQ日本語訳 ヌルポインタ

Category:データ型
Category:無