前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >g++中宏NULL究竟是什么?

g++中宏NULL究竟是什么?

作者头像
一见
发布2018-08-10 16:51:23
1.1K0
发布2018-08-10 16:51:23
举报
文章被收录于专栏:蓝天蓝天

g++中宏NULL究竟是什么?.pdf

NULL是个指针,还是个整数?0?或(void*)0?答案是和g++版本有关。g++ 4.6支持C++11,引入了nullptr,也许会发生变化。

可以写段简单代码求证一下:

代码语言:javascript
复制
#include
#include
int main()
{
printf("NULL: %d\n", NULL);
printf("sizeof(NULL): %d\n", sizeof(NULL));
printf("typeid(__null).name(): %s\n", typeid(__null).name());
printf("typeid(0).name(): %s\n", typeid(0).name());
return 0;
}

使用g++ 4.1.2(SuSE 10.1)编译,输出结果如下:

代码语言:javascript
复制
NULL: 0
sizeof(NULL): 8
typeid(__null).name(): l
typeid(0).name(): i

从输出结果,可以看到NULL是long类型的整数,定义应当是0L或0LL。

下面再借助gdb,来看一看它的真面目(博文:《GDB高级技巧》有介绍gdb的高级使用)。假设源文件名为x.cpp,使用如下方法编译:

代码语言:javascript
复制
g++ -g3 -gdwarf-2 -o x x.cpp

注意这里使用了参数“-g3 -gdwarf-2”。其中“-g3”不能是“-g”。

编译成功后,在gdb中跟踪运行程序,在main函数处打断点即可:

代码语言:javascript
复制
adoop@VM-39-166-sles10-64:~/current> gdb ./x
GNU gdb 6.6
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "x86_64-suse-linux"...
Using host libthread_db library "/lib64/libthread_db.so.1".
(gdb) b main
Breakpoint 1 at 0x4005dc: file x.cpp, line 6.
(gdb) r
Starting program: /data/hadoop/hadoop-2.4.0/x
Breakpoint 1, main () at x.cpp:6
6               printf("NULL: %d\n", NULL);
(gdb) macro expand NULL
expands to: __null
(gdb) p NULL
No symbol "__null" in current context.
(gdb) ptype NULL
No symbol "__null" in current context.
(gdb) p __null
No symbol "__null" in current context.
(gdb) ptype __null
No symbol "__null" in current context.
(gdb)

从gdb的跟踪结果,不难看到NULL的真身是__null,但__null又是什么了?试图从/usr/include中找到答案:

代码语言:javascript
复制
hadoop@VM-39-166-sles10-64:~/current> grep __null /usr/include/*
/usr/include/libio.h:#  define NULL (__null)
hadoop@VM-39-166-sles10-64:~/current> grep __null /usr/include/*/*
/usr/include/asm-i386/vm86.h:   long __null_ds;
/usr/include/asm-i386/vm86.h:   long __null_es;
/usr/include/asm-i386/vm86.h:   long __null_fs;
/usr/include/asm-i386/vm86.h:   long __null_gs;
/usr/include/asm-i386/vm86.h:   long __null_ds;
/usr/include/asm-i386/vm86.h:   long __null_es;

未能找到满意的答案,那么__null只能是g++内置定义的,所以未出现在任何头文件中,事实证明也如此,在代码中可以直接使用__null(尽管如此,但这个不是个好主意):

代码语言:javascript
复制
#include
#include
int main()
{
printf("NULL: %d\n", NULL);
printf("NULL: %d\n", __null);
printf("sizeof(NULL): %d\n", sizeof(NULL));
printf("typeid(__null).name(): %s\n", typeid(__null).name());
printf("typeid(0).name(): %s\n", typeid(0).name());
return 0;
}

执行man g++,然后搜索“__null”,找到一个有关的条目:

代码语言:javascript
复制
-Wstrict-null-sentinel (C++ only)
Warn also about the use of an uncasted "NULL" as sentinel.  When compiling only with GCC this is a valid sentinel, as "NULL" is defined to "__null".  Although it is a null pointer constant not a null pointer, it is guaranteed to of the same size as a pointer(保证和指针相同的大小).  But this use is not portable across different compilers.

搜索gcc 4.8.2源码中的FSFChangeLog.11文件:

代码语言:javascript
复制
Wed Aug  7 14:10:07 1996  Jason Merrill
* ginclude/stddef.h (NULL): Use __null for G++.

继续搜索gcc源代码,可以得到更多信息:

代码语言:javascript
复制
VM-39-166-sles10-64:/data/gcc-4.8.2/gcc # grep __null */*
c-family/c-common.c:  { "__null",               RID_NULL,       0 },
c-family/c-common.c:  /* Create the built-in __null node.  It is important that this is
c-family/c-common.c:      /* Although __null (in C++) is only an integer we allow it
c-family/c-common.h:/* The node for C++ `__null'.  */
cp/call.c:            /* If __null has been converted to an integer type, we do not
cp/NEWS:   is now defined as __null, a magic constant of type (void *)
cp/parser.c:     __null
cp/parser.c:      /* The `__null' literal.  */

进一步查看c-family/c-common.c文件:

代码语言:javascript
复制
const struct c_common_resword c_common_reswords[] =
{
{ "__is_union",       RID_IS_UNION,   D_CXXONLY },
{ "__label__",        RID_LABEL,      0 },
{ "__null",           RID_NULL,       0 },
{ "__real",           RID_REALPART,   0 },
{ "__real__",         RID_REALPART,   0 },
{ "__restrict",       RID_RESTRICT,   0 },

结构体c_common_resword的定义在c-family/c-common.h中:

代码语言:javascript
复制
/* The node for C++ `__null'.  */
#define null_node                       c_global_trees[CTI_NULL]
/* An entry in the reserved keyword table.  */
struct c_common_resword
{
const char *const word;
ENUM_BITFIELD(rid) const rid : 16;
const unsigned int disable   : 16;
};
enum c_tree_index
{
。。。。。。
CTI_VOID_ZERO,
CTI_NULL,
CTI_MAX
};

查看文件cp/parser.c,parser.c是C/C++语法解析器的实现文件:

代码语言:javascript
复制
static tree
cp_parser_primary_expression (cp_parser *parser,
bool address_p,
bool cast_p,
bool template_arg_p,
bool decltype_p,
cp_id_kind *idk)
{
。。。。。。
case CPP_KEYWORD:
switch (token->keyword)
{
/* These two are the boolean literals.  */
case RID_TRUE:
cp_lexer_consume_token (parser->lexer);
return boolean_true_node;
case RID_FALSE:
cp_lexer_consume_token (parser->lexer);
return boolean_false_node;
/* The `__null' literal.  */
case RID_NULL:
cp_lexer_consume_token (parser->lexer);
return null_node;
/* The `nullptr' literal.  */
case RID_NULLPTR:
cp_lexer_consume_token (parser->lexer);
return nullptr_node;

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2014-04-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档