C言語では、ゼロの値として、NULL
、NUL
、0
などの違いがあるようです。
私はASCII文字の'0'
が48
または0x30
と評価されることを知っています。
NULL` ポインタは通常次のように定義されます。
#define NULL 0
または
#define NULL (void *)0
さらに、NUL
文字 '0'
もありますが、これも同様に0
に評価されるようです。
この3つの値が等しくならない場合はありますか?
また、64ビットのシステムでもそうなのでしょうか?
**この回答は、C++ではなく、C言語に適用されます。
整数定数リテラル 0
は、使用される文脈によって異なる意味を持ちます。どのような場合でも、値が 0
の整数定数であることに変わりはありませんが、記述の仕方が異なるだけです。
ポインタが定数リテラル 0
と比較されている場合、これはポインタがヌルポインタであるかどうかを確認しています。この 0
は、ヌルポインター定数と呼ばれます。C標準では、void *
型にキャストされた 0
は、ヌルポインタであると同時にヌルポインタ定数でもあると定義されています。
また、可読性を高めるために、ヘッダファイル stddef.h
にマクロ NULL
が用意されています。コンパイラによっては、#undef NULL
と再定義して、何かおかしなものを作ることができるかもしれません。
そこで、NULLポインタをチェックする有効な方法をいくつか紹介します。
if (pointer == NULL)
NULLは null ポインタと比較するように定義されています。 有効なヌルポインター定数である限り、
NULL`の実際の定義が何であるかは実装で定義されています。
if (pointer == 0)
0` は null ポインタ定数の別の表現です。
if (!pointer)
この if
文は暗黙のうちに "is not 0" をチェックしているので、それを逆にして "is 0" を意味します。
以下はNULLポインタをチェックするINVALIDな方法です。
int mynull = 0;
<some code>
if (pointer == mynull)
コンパイラにとっては、これはヌルポインタのチェックではなく、2 つの変数の等値性チェックです。これは、mynull がコード内で変更されることがなく、コンパイラの最適化で if 文に 0 を折り畳むことが恒常的に行われていれば *動作するかもしれませんが、これは保証されておらず、コンパイラは C 規格に従って少なくとも 1 つの診断メッセージ(警告またはエラー)を生成する必要があります。
なお、C言語では何がヌルポインターなのか。それは、基礎となるアーキテクチャ上では重要ではありません。もし、基礎となるアーキテクチャがアドレス0xDEADBEEFとして定義されたヌルポインタの値を持っている場合、この混乱を解決するのはコンパイラ次第です。
そのため、このようなおかしなアーキテクチャであっても、以下の方法はヌルポインターをチェックする有効な方法です。
if (!pointer)
if (pointer == NULL)
if (pointer == 0)
以下の方法は、ヌルポインターをチェックするための無効な方法です。
#define MYNULL (void *) 0xDEADBEEF
if (pointer == MYNULL)
if (pointer == 0xDEADBEEF)
コンパイラはこれらを通常の比較と見なします。
は、すべてのビットがゼロに設定された文字であるヌル文字と定義されています。これはポインターとは関係ありません。しかし、以下のようなコードを目にすることがあります。
if (!*string_pointer)
文字列ポインタがヌル文字を指しているかどうかをチェックする
if (*string_pointer)
文字列ポインタが非ヌル文字を指しているかどうかをチェックします。
これらをヌルポインターと混同しないでください。ビット表現が同じなので、便利なクロスオーバーが可能になりますが、実際には同じものではありません。
さらに、'0'
は(他の文字リテラルと同様に)整数の定数であり、この場合は値がゼロです。 つまり、'0'
は、何の飾りもない0
の整数定数と完全に同じです。唯一の違いは、それが人間の読者に伝える意図です("I'm using this as a null character.")。
詳しくはcomp.lang.c FAQのQuestion 5.3をご覧ください。 C標準についてはこのpdfをご覧ください。6.3.2.3 Pointersの第3項をご覧ください。
NULLは 0 であることが保証されているわけではなく、その正確な値はアーキテクチャに依存します。ほとんどの主要なアーキテクチャでは
(void*)0` と定義されています。
これはバイト0が文字リテラルでどのようにエンコードされているかを表しています。
C言語のコンパイラがASCIIを使う必要があるかどうかは覚えていませんが、もしそうでなければ、'0'
は常に48とは限らないでしょう。いずれにしても、よほど曖昧なシステムを扱っていない限り、EBCDICのような代替文字セットを使うシステムに遭遇することはないでしょう。
64ビットシステムでは、さまざまなタイプのサイズが異なりますが、整数値は同じになります。
コメントの中には,NULLは0に等しいが,*0ではないのではないかという疑問があります.以下にプログラムの例と、そのようなシステムで期待される出力を示します。
#include <stdio.h>
int main () {
size_t ii;
int *ptr = NULL;
unsigned long *null_value = (unsigned long *)&ptr;
if (NULL == 0) {
printf ("NULL == 0\n"); }
printf ("NULL = 0x");
for (ii = 0; ii < sizeof (ptr); ii++) {
printf ("%02X", null_value[ii]); }
printf ("\n");
return 0;
}
このプログラムは次のように出力します。
NULL == 0
NULL = 0x00000001