g++中宏NULL究竟是什么?
NULL是个指针,还是个整数?0?或(void*)0?答案是和g++版本有关。g++ 4.6支持C++11,引入了nullptr,也许会发生变化。
可以写段简单代码求证一下:
#include <stdio.h> #include <typeinfo> 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)编译,输出结果如下:
NULL: 0 sizeof(NULL): typeid(__null).name(): l typeid(0).name(): i |
从输出结果,可以看到NULL是long类型的整数,定义应当是0L或0LL。
下面再借助gdb,来看一看它的真面目(博文:《GDB高级技巧》有介绍gdb的高级使用)。假设源文件名为x.cpp,使用如下方法编译:
g++ -g3 -gdwarf-2 -o x x.cpp |
注意这里使用了参数“-g3 -gdwarf-2”。其中“-g3”不能是“-g”。
编译成功后,在gdb中跟踪运行程序,在main函数处打断点即可:
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中找到答案:
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(尽管如此,但这个不是个好主意):
#include <stdio.h> #include <typeinfo> 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”,找到一个有关的条目:
-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文件:
Wed Aug 7 14:10:07 1996 Jason Merrill <jason@yorick.cygnus.com> * ginclude/stddef.h (NULL): Use __null for G++. |
继续搜索gcc源代码,可以得到更多信息:
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: <stddef.h> 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文件:
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中:
/* 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++语法解析器的实现文件:
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; |
g++中宏NULL究竟是什么?的更多相关文章
- C++ 中宏的使用 --来自:http://blog.csdn.net/hgl868/article/details/7058906
宏在代码中的使用实例: g_RunLog2("Middleware client for Linux, build:%s %s", __DATE__, __TIME__); 下面详 ...
- ATL中宏定义offsetofclass的分析
近日学习ATL,通过对宏定义offsetofclass的解惑过程.顺便分析下虚函数表,以及通过虚函数表调用函数的问题. 1 解开ATL中宏定义offsetofclass的疑惑 #define _ATL ...
- Oracle中的null
测试数据:公司部分员工基本信息
- 正则表达式(/[^0-9]/g,'')中的"/g"是什么意思 ?
正则表达式(/[^0-9]/g,'')中的"/g"是什么意思 ? 表达式加上参数g之后,表明可以进行全局匹配,注意这里“可以”的含义.我们详细叙述: 1)对于表达式对象的e ...
- SQL中的Null深入研究分析
SQL中的Null深入研究分析 虽然熟练掌握SQL的人对于Null不会有什么疑问,但总结得很全的文章还是很难找,看到一篇英文版的, 感觉还不错. Tony Hoare 在1965年发明了 null 引 ...
- 深入详解SQL中的Null
深入详解SQL中的Null NULL 在计算机和编程世界中表示的是未知,不确定.虽然中文翻译为 “空”, 但此空(null)非彼空(empty). Null表示的是一种未知状态,未来状态,比如小明兜里 ...
- 给定一个字符串里面只有"R" "G" "B" 三个字符,请排序,最终结果的顺序是R在前 G中 B在后。 要求:空间复杂度是O(1),且只能遍历一次字符串。
题目:给定一个字符串里面只有"R" "G" "B" 三个字符,请排序,最终结果的顺序是R在前 G中 B在后. 要求:空间复杂度是O(1),且 ...
- JAVA中String = null 与 String = "" 的区别
JAVA中String = null 与 String = ""的区别 笔者今天在Debug的时候发现的NPE(NullPointerException),辛辛苦苦地调试了半天,终 ...
- _DataStructure_C_Impl:求图G中从顶点u到顶点v的一条简单路径
#pragma once #include<stdio.h> #include<stdlib.h> #define StackSize 100 typedef int Data ...
随机推荐
- fir 窗口设计法
加窗的原因.对于理想的低通滤波器H(exp(jw)),其h(n)是无限长序列.这是可以证明的.因此为了得到有限长的h(n)就需要截断,而这个过程就是加窗.由于h(n)截断即其频率响应就和理想的低通滤波 ...
- 代做JSP课程设计,毕业设计
代做JSP课程设计,毕业设计,大家都是学生,绝对靠谱,有意者加我Q 279283855
- C# 设计模式-工厂模式(Factory)
1.工厂模式 factory从若干个可能类创建对象. 例如:如果创建一个通信类接口,并有多种实现方式,可以使用factory创建一个实现该接口的对象,factory可以根据我们的选择,来创建适合的对象 ...
- C# 泛型编程之泛型类、泛型方法、泛型约束
来自Hauk的文章 C# 泛型编程之泛型类.泛型方法.泛型约束 所谓泛型,即通过参数化类型来实现在同一份代码上操作多种数据类型. 泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为 ...
- 【微信小程序常识】如何绑定微信小程序体验者
转自:https://blog.csdn.net/futruejet/article/details/53223826 一.操作步骤 (1)打开微信小程序公众平台->点击右边菜单[用户身份]-& ...
- poi操作word 2007 常用方法总结
import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io ...
- 留存- angularjs 弹出框 $modal
$modal只有一个方法:open,该方法的属性有: templateUrl:模态窗口的地址 template:用于显示html标签 scope:一个作用域为模态的内容使用(事实上,$modal会创建 ...
- VS2017 Intelligense C++ 设置的几个重点
1,高级-点到箭头的转换,用于指针操作 2,高级-成员列表筛选模式-一定要选[模糊],而不要选[智能] 这样在我们输入 vkphdfea就能检索到vkPhysicalDeviceFeatures, 而 ...
- git如何处理别人的pull request及解决冲突 (转)
原贴地址 出过两次了,每次都查很多资料,太蛋疼,记录在此. 当你的项目比较牛逼的时候,有人给你贡献代码,但他修改的地方恰恰你前阵子也修改了,这样在github中就不能够自动merge了. 因此你需要手 ...
- tomcat https
转自 http://11lingxian.iteye.com/blog/1491607 双向认证: 客户端向服务器发送消息,首先把消息用客户端证书加密然后连同时把客户端证书一起发送到服务器端, 服务器 ...