ずっと勘違いしてたんですけど,mixi のなつさんたんの日記経由できむら(K)さんに教えてもらいました.
C FAQ 5章 ヌルポインター
ポインタの文脈で出てきた定数 0 は,NULL の内部表現が何であれ,かならずぬるぽ扱いされることが規格で保証されているそうな.
ほえー,知らなかった…
次期 C++ 0x では nullptr とかが提案されてるそうです.しかしまぁ,結局後方互換性のために,コンパイラは定数 0 と,環境依存の NULL の定義と,仕様の nullptr 全部を特別扱いしないといけなくなるだけなので,なんだかなぁという気もします.
ところで,手元の NULL の定義はどうなってるんだろうなと.
$ cat null.c #include int main() { int *p = NULL; }
$ cpp -E null.c # 1 "null.c" # 1 "" # 1 "<コマンドライン>" # 1 "null.c" # 1 "/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/include/stddef.h" 1 3 4 # 152 "/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/include/stddef.h" 3 4 typedef int ptrdiff_t; # 214 "/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/include/stddef.h" 3 4 typedef unsigned int size_t; # 326 "/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/include/stddef.h" 3 4 typedef long int wchar_t; # 2 "null.c" 2 int main() { int *p = ((void *)0); }
C なので見慣れた (void *)0 に.
/usr/local/lib/gcc/i686-pc-linux-gnu/4.1.1/include/stddef.h を見てみると.
/* A null pointer constant. */
#if defined (_STDDEF_H) || defined (__need_NULL) #undef NULL /* in case has defined it. */ #ifdef __GNUG__ #define NULL __null #else /* G++ */ #ifndef __cplusplus #define NULL ((void *)0) #else /* C++ */ #define NULL 0 #endif /* C++ */ #endif /* G++ */ #endif /* NULL not defined and or need NULL. */ #undef __need_NULL
C++ の場合は ((void *)0) をポインタの文脈で暗黙的にキャストできないから,定数 0 にする.
g++ では __null とかいう,謎の予約語が使われるらしい.
gcc-4.3.0/gcc/c-common.h
/* A node for `((void) 0)'. */ #define void_zero_node c_global_trees[CTI_VOID_ZERO]
/* The node for C++ `__null'. */ #define null_node c_global_trees[CTI_NULL]
gcc-4.3.1/gcc/cp/lex.c
static const struct resword reswords[] = { ... { "__null", RID_NULL, 0 }, ...
gcc-4.3.1/gcc/cp/parser.c
/* Expressions [gram.expr] */
/* Parse a primary-expression.
primary-expression: literal this ( expression ) id-expression
GNU Extensions:
primary-expression: ( compound-statement ) __builtin_va_arg ( assignment-expression , type-id ) __builtin_offsetof ( type-id , offsetof-expression )
C++ Extensions: __has_nothrow_assign ( type-id ) __has_nothrow_constructor ( type-id ) __has_nothrow_copy ( type-id ) __has_trivial_assign ( type-id ) __has_trivial_constructor ( type-id ) __has_trivial_copy ( type-id ) __has_trivial_destructor ( type-id ) __has_virtual_destructor ( type-id ) __is_abstract ( type-id ) __is_base_of ( type-id , type-id ) __is_class ( type-id ) __is_convertible_to ( type-id , type-id ) __is_empty ( type-id ) __is_enum ( type-id ) __is_pod ( type-id ) __is_polymorphic ( type-id ) __is_union ( type-id )
Objective-C++ Extension:
primary-expression: objc-expression
literal: __null
ADDRESS_P is true iff this expression was immediately preceded by "&" and therefore might denote a pointer-to-member. CAST_P is true iff this expression is the target of a cast. TEMPLATE_ARG_P is true iff this expression is a template argument.
Returns a representation of the expression. Upon return, *IDK indicates what kind of id-expression (if any) was present. */
static tree cp_parser_primary_expression (cp_parser *parser, bool address_p, bool cast_p, bool template_arg_p, cp_id_kind *idk) { ... /* The `__null' literal. */ case RID_NULL: cp_lexer_consume_token (parser->lexer); return null_node;
|