法大奥山研究室

 previous  contents

10.8. NULLポインタ (空ポインタ)


 char 型には '\0''A' など,int 型には10進数表記で 0 や16進数表記で 0x00 などの「定数」がありました(付録4.A)。ポインタ(char* 型や int* 型など)には,つぎの「定数」が用意されています。

[ノート]ISO規格C11(旧C99)の原文は,つぎの通りです。
[§6.3.2.3, 3] An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.
[§6.3.2.3, fn.66] The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant.
[§7.19, 3] NULL ... expands to an implementation-defined null pointer constant[.]
"a" や "an" とあるように,空ポインタ定数は,一つだけではありません。
その中でも,定数 NULL の定義は,処理系依存になっています。試しにヘッダ stddef.h を開いて,マクロ NULL を確認してみましょう。
[参考]奥山研究室のコンパイラ gcc では マクロ NULL(void*)0 と定義されていましたが,他のコンパイラで同じように定義されているとは限りません。

これらの「定数」を使って,つぎの「空ポインタ」が出来上がります。

[ノート]ISO規格C11(旧C99)の原文は,つぎの通りです。
[§6.3.2.3, 3] If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
[§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.

/* Example 10.11 */

#include <stdio.h>

int main(void)
{
       void *p = 0x0;                     // 右辺は空ポインタ定数なので,p は空ポインタ
       int *q = 0x0;                      // 整数定数式 0x0 が空ポインタ定数か否かを(1)や(8)(9)で確認
       int n = 0;


       /* A */
       printf("(A) p [%p]\n", p);         // %p の出力は処理系依存;後出 13.1 参照

       if(p == NULL)                      // (1) NULL は処理系依存の空ポインタ定数
                                          //     if文については,後出 14.3 参照
              printf("OK, integer constant expression 0x0 "
                     "is a null pointer constant in your computer.\n");
       else
              printf("* WARNING\n"
                     "* Integer constant expression 0x0 may not be "
                     "with \"the value 0\" in your computer.\n"
                     "* Or, NULL may be incompatible with ISO:C11.\n");


       /* B */
       p = (void *)0;                     // (2) 右辺は空ポインタ定数なので,p は空ポインタ
                                          //     (void *)0 が空ポインタ定数か否かを(3)で確認
       printf("(B) p [%p]\n", p);

       if(p == NULL)                      // (3)
              printf("OK, (void *)0 is a null pointer constant in your computer.\n");
       else
              printf("* WARNING\n"
                     "* Integer constant expression 0 may not be "
                     "with \"the value 0\" in your computer.\n"
                     "* Or, NULL may be incompatible with ISO:C11.\n");


       /* C */
       printf("(C) p [%p]\n"
              "    q [%p]\n", p, q);

       if(q == (int *)p)                  // (4)
              printf("OK, any two null pointers shall compare equal "
                     "[C11 \u00A76.3.2.3, 4; \u00A76.5.9, 6].\n");
       else
              printf("* WARNING\n"
                     "* Either integer constant expression 0x0 or 0 may not be "
                     "with \"the value 0\" in your computer.\n");


       /* D */
       q = &n;                            // (5) 右辺は空ポインタ定数でもなければ,空ポインタでもないので,
                                          //     q は空ポインタではない
       printf("(D) q [%p]\n", q);

       if(q != NULL)                      // (6)
              printf("OK, q is not a null pointer.\n");
       else
              printf("* WARNING\n"
                     "* NULL may be broken.\n");


       /* E */
       p = 0x0;                           // (7)

       printf("(E) p [%p]\n"
              "    q [%p]\n", p, q);

       if(q != p)                         // (8)
              printf("OK, q is not a null pointer.\n");
       else
              printf("* WARNING\n"
                     "* Integer constant expression 0x0 may not be "
                     "with \"the value 0\" in your computer.\n");

       
       /* F */
       printf("(F) q [%p]\n", q);

       if(q != 0x0)                      // (9)
              printf("OK, q is not a null pointer.\n");
       else
              printf("* WARNING\n"
                     "* Integer constant expression 0x0 may not be "
                     "with \"the value 0\" in your computer.\n");


       return 0;
}

奥山研究室では gcc -Wall で no errors & no warnings,つぎの実行結果を得ます。
* UTF未対応のターミナルでの実行の場合には,§ が \u00A7 と出力されたり,文字化けするかもしれません(その場合は,上記プログラムの中の \u00A7 を削除してからコンパイルしてください)。Macユーザの方は,Terminal.app にて実行してみてください。

(A) p [0x0]
OK, integer constant expression 0x0 is a null pointer constant in your computer.
(B) p [0x0]
OK, (void *)0 is a null pointer constant in your computer.
(C) p [0x0]
    q [0x0]
OK, any two null pointers shall compare equal [C11 §6.3.2.3, 4; §6.5.9, 6].
(D) q [0x7fff5142bb8c]
OK, q is not a null pointer.
(E) p [0x0]
    q [0x7fff5142bb8c]
OK, q is not a null pointer.
(F) q [0x7fff5142bb8c]
OK, q is not a null pointer.

Example 10.11の(2)(5)(7)には,単純代入演算子 = が使われています。ポインタに対する文法は,つぎの通りです。

なお,void へのポインタには,つぎの変換法則があります。

上記(1)(3)(4)(6)(8)(9)の if文内の等価演算子 ==!= に対するポインタの使用については,つぎの文法があります。

3つ目の文法での空ポインタ定数(NULLポインタ定数)は,もう一方のオペランドのポインタ型に変換されます[C11(旧C99)§6.5.9, 5]。よって,空ポインタとして,もう一方のオペランドのポインタと比較されます。

等価演算子 == においてポインタ同士が「等しい」と判定される,すなわち,演算式が 1 を返すのは,つぎのケースです。

[ノート]ISO規格C11(旧C99)の原文は,つぎの通りです。
[§6.5.9, 6] Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function, both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.

最後に,関係演算子上の文法を再述 (7.4) しておきます。


 previous  contents