コンピューティングにおいて、ヌルポインタ(nullptrまたはnullと略されることもあります)またはヌル参照とは、ポインタまたは参照がオブジェクトを参照していないことを示す値です。プログラムは、長さが不明なリストの末尾や何らかのアクションの実行失敗などの状態を表すために、ヌルポインタを日常的に使用します。このヌルポインタの使用方法は、null許容型やオプション型のNothing値と比較できます。
ヌルポインタは、初期化されていないポインタと混同してはいけません。ヌルポインタは、オブジェクトを指すポインタとは必ず等しくないことが保証されています。しかし、一般的に、ほとんどの言語では、初期化されていないポインタに対してそのような保証は提供されていません。他の有効なポインタと等しい場合もあれば、ヌルポインタと等しい場合もあります。異なるタイミングで両方の結果になる場合もあれば、比較が未定義の動作になる場合もあります。また、そのようなサポートを提供する言語では、正しい使用方法は、各開発者とリンターツールの個々の経験に依存します。適切に使用した場合でも、ヌルポインタは意味的に不完全です。なぜなら、「適用不可」、「現在不明」、「まだ決定されていない」値の違いを表現する手段を提供しないからです。[ 1 ]
タグ付きアーキテクチャを採用したシステムでは、ヌルポインタをタグ付き共用体に置き換えることで、例外的なケースを明示的に処理することができます。実際、ヌルポインタは、計算されたタグを持つタグ付きポインタとみなすことができます。
ヌルポインタは意味のあるオブジェクトを指していないため、その(無効な)メモリ位置に格納されているデータにアクセスしようとすると、実行時エラーやプログラムの即時クラッシュが発生する可能性があります。これがヌルポインタエラー、またはヌルポインタ例外です。これは最も一般的なソフトウェアの脆弱性の1つであり、[ 2 ]この概念を導入したトニー・ホーアはこれを「10億ドルのミス」と呼んでいます。[ 3 ]
Cでは、任意の型の 2 つのヌル ポインタは必ず等しいと比較されます。[ 4 ]プリプロセッサ マクロNULLが提供されており、実装定義のヌル ポインタ定数として定義されています。[ 5 ]これはC99では、整数値を型に変換して移植可能な形で表現できます( void 型へのポインタを参照)。[ 6 ] C23以降、ヌル ポインタは型(C++11 で初めて導入)で表現され、型安全なヌル ポインタを提供します。[ 7 ]<stdlib.h>#define NULL ((void*)0)0void*nullptrnullptr_t
C 標準では、ヌル ポインタがメモリ アドレス0へのポインタと同じであるとは規定されていませんが 、実際にはそうなる場合もあります。ヌル ポインタの逆参照はC では未定義の動作であり、[ 8 ]準拠する実装では、逆参照されるポインタはヌルではないと仮定することが認められています。
実際には、ヌルポインタを逆参照すると、マッピングされていないメモリからの読み取りまたは書き込みが試行され、セグメンテーション違反またはメモリアクセス違反が発生する可能性があります。これは、プログラムのクラッシュとして現れる場合もあれば、プログラムコードで捕捉できるソフトウェア例外に変換される場合もあります。ただし、そうでない状況もあります。たとえば、x86リアルモードでは、アドレス0000:0000は読み取り可能であり、通常は書き込みも可能であり、そのアドレスへのポインタを逆参照することは、完全に有効ですが、通常は望ましくない操作であり、アプリケーションで未定義のクラッシュしない動作につながる可能性があります。ヌルポインタがそのアドレスへのポインタとして表現されている場合、それを逆参照すると、その動作につながります。アドレス 0 へのポインタを逆参照することが意図的で明確に定義されている場合もあります。たとえば、16 ビット リアルモード x86 デバイス用に C で記述されたBIOSコードは、書き込み用のヌルポインタと同じ値のポインタを逆参照することにより、マシンの物理アドレス 0 に割り込み記述子テーブル(IDT)を書き込むこと があります。コンパイラがヌルポインタの逆参照を最適化して削除し、セグメンテーション違反を回避することも可能だが、他の望ましくない動作を引き起こす可能性がある。[ 9 ]
C++では、NULLマクロは C から継承されましたが、ヌルポインタ定数を表すには、従来からゼロの整数リテラルが好まれてきました。[ 10 ]しかし、C++11では、代わりに明示的なヌルポインタ定数nullptrと型が導入されnullptr_t、型安全なヌルポインタが提供されるようになりました。nullptrと型はnullptr_t、後に C23 で C に導入されました。
プログラミング言語によって、ヌルポインタを表すリテラルは異なります。JavaとC# では、参照型のリテラルとして提供されます。PascalとSwiftでは、ヌルポインタは と呼ばれます。Eiffel では、参照と呼ばれます。Rust では、値がないことは で表されますが、真のヌルポインタは です。nullnilvoidNonestd::ptr::null()
ヌルポインタは意味のあるオブジェクトを指していないため、ヌルポインタを逆参照(つまり、そのメモリ位置に格納されているデータにアクセス)しようとすると、通常は(常にではありませんが)実行時エラーまたはプログラムの即時クラッシュが発生します。MITREは、ヌルポインタエラーを最もよく悪用されるソフトウェアの脆弱性の1つとして挙げています。[ 11 ]
SIGSEGVtrycatchstd::signal()NullPointerException。Javaではjava.lang.NullPointerExceptionを継承しますがjava.lang.RuntimeException、Poco::NullPointerExceptionは を継承しますPoco::LogicException。[ 12 ]Null_Exception。nilメモリ内の最初のアドレスへのヌルポインタを表し、管理対象変数の初期化にも使用されます。この定数を逆参照すると、外部 OS 例外が発生し、ユニットが句内でリンクされているEAccessViolation場合は、その例外が Pascal 例外インスタンスにマッピングされます。System.SysUtilsusesnull)にアクセスするとNullPointerException、NPE (NullPointerException) が発生します。これはエラー処理コードで捕捉できますが、推奨される方法は、このような例外が発生しないようにすることです。null) にアクセスすると例外がSystem.NullReferenceExceptionスローされます。これらの例外をキャッチすることは一般的に好ましくないと考えられていますが、この例外タイプはプログラムでキャッチして処理することができます。nilプログラムを中断することなく、オブジェクト (ヌルポインタ)にメッセージを送信できます。メッセージは単に無視され、戻り値 (存在する場合) は型に応じてnilまたは になります。 [ 13 ]0std::ptr::null())を逆参照するとunsafe未定義の動作が発生し、通常はセグメンテーション違反またはメモリ破損が発生します。ヌルがない言語も存在するかもしれないが、ほとんどの言語にはヌルが存在する可能性があるため、ヌルポインタの逆参照を回避したりデバッグを支援したりする手法が存在する。[ 15 ] Bond らは、ヌル伝播を追跡するためにJava 仮想マシン(JVM) を変更することを提案している。[ 15 ]
null参照の処理には、効果の高い順に3つのレベルがあります。
純粋関数型言語は、ポインタへの直接アクセスが一切提供されず、すべてのコードとデータが不変であるため、レベル1の例と言えます。インタプリタ型言語や仮想マシン言語で実行されるユーザーコードは、一般的にヌルポインタの逆参照の問題に悩まされることはありません。
言語が void になる可能性のあるポインタを提供または利用する場合、静的解析やその他の手法によるコンパイル時チェックを提供することで、実行時の null 参照を回避することが可能です。構文的には、null 参照を回避するために Void 安全性を備えた Eiffel プログラミング言語 [ 16 ]、D [ 17 ]、Rust [ 18 ] に見られるような言語機能から支援されます。null許容型システムは、主流のプログラミング言語でも広く採用されています。Kotlin 、Swift、TypeScript は最初からそれらを含み、C#とScala はnull 許容型システムが後付けされています。[ 19 ]
一部の言語では、外部ツールを使用して解析を実行できますが、言語定義自体によって制限されるため、コンパイラによるチェックなどの直接的な言語サポートに比べると劣ります。
レベル3の最終手段は、実行時にヌル参照が発生した場合です。デバッグツールが役立つ場合があります。
2009年、トニー・ホーアは[ 3 ] [ 20 ] [ 21 ] 、1965年にALGOL W言語の一部としてヌル参照を発明したと述べた。その2009年の記述の中で、ホーアは自身の発明を「10億ドルの失敗」と表現している。
私はこれを「10億ドルの過ち」と呼んでいます。それは1965年にヌル参照を発明したことです。当時、私はオブジェクト指向言語(ALGOL W)における参照のための初の包括的な型システムを設計していました。私の目標は、コンパイラによる自動チェックによって、すべての参照使用が絶対に安全であることを保証することでした。しかし、実装が非常に簡単だったため、ヌル参照を導入するという誘惑に抗えませんでした。これが無数のエラー、脆弱性、システムクラッシュを引き起こし、過去40年間で恐らく10億ドルもの損害と損失をもたらしたのです。
constNULLNULL 0-201-88954-4。{{cite book}}: CS1 maint: 複数名: 著者リスト (リンク) CS1 maint: 数値名: 著者リスト (リンク)