C++中的NULL和Java中的null有什么区别?

20
我一直在努力理解为什么C ++ 让我敲 NULL 这个单词时感到疯狂。突然有一天我想到,在Java中我已经敲了多年的 null (小写)。现在我突然开始编写C++,这个小小的肌肉记忆碎片让我感到疯狂。
Wikiperipatetic 将 C ++ 的 NULL 定义为 stddef 的一部分:

一个宏展开成一个空指针常量。它可以被定义为 ((void*)0),0或0L,具体取决于编译器和语言。

Sun 的文档告诉我关于 Java 的“ null 字面值”:

空类型只有一个值:空引用,由文字表示形式 null 表示,该文字由 ASCII 字符形成。空字面值始终是空类型。

所以这一切都很好。我知道什么是空指针引用,感谢编译器笔记。现在我对 Java 中的字面值有点模糊,因此我继续阅读……

字面值是固定值的源代码表示形式。文字直接在您的代码中表示,无需计算。

还有一个特殊的空字面值,可以用作任何引用类型的值。空可以分配给任何变量,除了基本类型变量。除了测试其存在之外,你几乎无法对空值做任何事情。因此,在程序中经常使用 null 作为标记,表示某个对象不可用。

好了,我想我现在明白了。在 C++ 中,NULL 是一个宏,在编译时计算为 null 指针常量。在 Java 中,null 是一个固定值,任何非基本类型都可以赋值;用于方便地在 if 语句 中进行测试。

Java没有指针,所以我可以理解为什么他们保持null是一个简单的值而不是什么花哨的东西。但是为什么java决定将所有大写字母的NULL更改为小写字母的null?

此外,我有没有漏掉什么?


7
“Java 没有指针”实际上,Java 只有指针。 - Viktor Sehr
1
在C++中,((void*)0) 不是NULL的有效定义。 - Mike Seymour
5
不正确。Java没有指针。即使一些实现(甚至所有实现)决定通过物理指针来实现Java对象的概念,仍然不意味着在Java中对象是指针。 - AnT stands with Russia
2
@AndreyT。Java对象显然不是指针。Java对象就是Java对象。@Viktor的意思是不能将对象存储在变量中,而只能存储对对象的引用,这是正确的。 - aioobe
@Stephano,Wikiperipatetic是什么意思? - Pacerier
显示剩余5条评论
10个回答

23
  • NULL是一个预处理器指令标识符,按照惯例,这些应该全部大写。

  • null是一个语言字面量,表示一个常数值,按照惯例应该全部小写(就像truefalse一样)。


3
认识你很高兴,回答不错。那么,你有什么想法为什么他们有这个规定吗?你知道他们一定是坐在桌前讨论真/假/空值,然后想着...“嗯,我们正在改变空值…” - Stephano
2
@Stephano 他们可能没有围坐在一起谈论它。在C++中,“true”和“false”都是小写字母。这是一个非常普遍的约定。一旦Java决定把“没有对象”的概念作为内置常量,它就需要遵循约定。因此,就有了“null”。 - moswald
2
除了所有关键字都是小写之外,我真的想不出任何好的答案。也许他们只是想强调它不是任何宏,而实际上是语言规范的一部分。说实话,我认为他们并没有将其视为从C++ NULL的“更改”。 - aioobe
我觉得我只是个疯子。我想象Bjarne在90年代末的一个早晨穿着他的睡衣,试图编写一个if(foo == NULL)并咒骂Java的疯狂小写。 - Stephano
2
我一直认为它们被大写是为了让你知道它们不是语言的一部分,甚至在编译器看到它们之前就被替换了,并且可能会产生副作用。例如MAX(a, ++b)如果预处理器将"b++"放置两次,则可能不会按照您的意图执行。在我看来,这种大写约定起到了警示作用,并提示您在哪里查找定义(/include而不是/lib)。 - Vagrant

22

Java的null更像C++0x的nullptr。在C++中,NULL仅仅是0,并且可能最终解析为int而不是指针,这并不是你想要的。考虑以下代码:


void f(int);
void f(char*);

...

f(NULL); // which f()?

C++0x有nullptr,解决了这个问题,但它仍然不能完全等同于Java的null。它们只是不同的语言。

另一个区别是Java没有指针(或者它这样说)。在Java中,你可以合法地将null分配给引用,在C++中,如果没有使用不良构造,就不能这样做。诚然,没有这种能力,Java几乎无用,但这绝对是另一个重要的区别。


4
Java引用具有C++指针和C++引用的某些属性,因此直接比较它们很困难。 - Tyler McHenry
2
不,Java的null与C++的nullptr没有任何相似之处,因为Java没有指针,而C++的nullptr严格限于指针。 - AnT stands with Russia
1
+1 很棒的回答,不过你漏掉了关于大写字母的部分。不管怎样,我认为人们通常对此不太感兴趣。显然我是个古怪的人。 - Stephano
1
@Stephano - 是的,我是这样做的。我真的不知道Sun为什么这样做。这里的其他答案有些说得通,但最终我认为这都只是猜测。除非我们能在某个地方找到文档记录,否则除了Sun之外没有人真正知道。 - Edward Strange
2
我完全不知道我在引发一场“Java指针是/否”的争论。我同意Noah的观点,那是离题了。请不要对回答问题但冒犯了你敏感的代码观点的人进行负面评价。 - Stephano
显示剩余5条评论

6
关于你的最后一个问题,我不确定小写的null设计理念背后是什么,但我认为目标是使null成为语言级别的字面量(比如true或false),而不是常数。
Java中的关键词通常是小写的,以及命名的字面量。常量(比如Integer.MAX_VALUE)通常是大写的。

+1 也是一个很好的答案。我不得不去查找一堆常量,但它们似乎大多数都是大写的。这是一个有趣的观点。 - Stephano
5
作为翻译,我想指出C语言没有truefalse关键字,但头文件通常会使用#define TRUE 1#define FALSE 0进行定义。C语言中的NULL也符合这种模式。 - Steven Sudit

2

使用0代替NULL

来自C++语言创始人Bjarne Stroustrup的书籍《C++程序设计语言》:

在C中,定义一个宏NULL来表示零指针很受欢迎。由于C++具有更严格的类型检查,使用纯粹的0而不是任何建议的NULL宏会导致更少的问题。如果你觉得必须定义NULL,请使用const int NULL = 0;


哇,非常有趣。那么我可以这样说吗:(类) Node n = 0;? - Stephano
它必须是Node *n = 0,因为0是一个(null)指针。换句话说,由于没有任何对象可以在内存0中拥有地址,因此在这种情况下,0表示指针不指向Node类的任何实例。否则,看起来你正在尝试将Node强制转换为整数。 - metaliving
1
对的,C++中的NULL是0,而C中的NULL更常见为(void*)0。 - Steven Sudit
+1,教我了一些很酷的东西。我不知道Node* n = 0;是有效的。 - Stephano
@Metaliving 我想你是指将整数强制转换为节点,如果省略 * 的话。 - starblue

2
不错,你已经基本理解了。在C ++中,空指针是分配给指针的任何文字零值。 NULL只是0的宏,因此ptr = 0ptr = NULL是相同的。它仅用于方便/可读性。它的大写是因为在C和C ++中有一个长期惯例,即宏的名称应该是大写的。
在Java中,null是内置字面量,由于它不是宏(而且Java根本没有宏的概念),因此没有强制要求将其大写。

2
Java中的null关键字用于标识变量不引用任何对象。null关键字不能赋值给使用基本数据类型声明的变量。C++中的NULL值是一个常量,定义为0。

1
在C++中,NULL是一个宏,编译时定义了空指针常量。
你的理解有误。在C++中,NULL就是0,没有其他含义。指针和整数都可以是NULL。
而在Java中,null是一个空指针,只有对象可以为null。

我不会说这是错误的。NULL是一个宏,它被评估为空指针常量0。它并没有定义空指针上下文,但我认为这只是一个模棱两可的词语选择问题。 - Tyler McHenry
那个词选择不太好。我已经改成了“求值为”。 - Stephano
1
@两个评论 - 这位发帖者是正确的,这是一个重要的事情需要注意。NULL不是指针常量,它是一个整数常量。恰好,NULL的值为0,在指针值的上下文中使用时也会评估为空指针。但正如我在自己的帖子中提到的那样,NULL将在指针之前解析为整数,因为这实际上就是它的本质。 - Edward Strange

1

Java没有指针,正如你所说的那样,这就是为什么在Java和C++之间,“null”的概念完全无法比较。

你的问题就像“角度和苹果之间的区别是什么”,即除了显而易见的答案外,无法以其他方式回答:C++中的NULL和Java中的null是两个完全不相关的概念。

Java从未“决定”将所有大写字母NULL更改为null,因为再次强调,Java的null与C++的NULL没有任何关系。


2
从另一个角度来看,Java主要是指针,因此概念非常接近。 - David Thornley
安德烈:严格来说是对的,但实际上是错误的。你说Java缺少指针,这是事实,但它的引用非常类似于C/C++的指针。 - Steven Sudit

0

其实我不知道为什么Java要把NULL改成null,但是全部大写字母键入起来更麻烦(至少在我的观点里是这样)。但你或许可以向Sun公司询问一下 :-P。总之,说Java没有指针并不完全正确,因为Java或C#等语言中的普通引用更像指针而不是C++中的引用。例如,在C++中,引用不能为NULL,但在Java中,引用可以为NULL。在C++中,引用不能更改其所指向的变量(在这一点上我可能错了),但在Java中引用可以。


0
指针基本上是内存地址。而且只有一个众所周知和已建立的内存地址,即0。C++中的NULL大写是因为它是预处理器宏,按照惯例它们总是大写的。指针概念直接映射到硬件中地址空间的概念。
Java使用引用,并且它有自己的内部表示方式。有一个众所周知的引用,null。它小写是因为它基本上是另一个符号,尽管是指代一个字面值。我认为他们从C到Java没有“改变”任何东西。我认为他们只是想要null概念,所以称之为“null”。
在两种情况下,null允许函数返回附加信息。它可以返回结果的地址和操作可能不成功的事实。

1
在C和C++中使用0作为空指针并不是基于内存位置0是特殊的想法,尽管通常是这样实现的。一个常量整数0将被强制转换为空指针常量。 - David Thornley
我并不是说内存位置0很特别,只是它是众所周知的,并且被用作惯例来表示指针不是一个有效的地址。 - Vagrant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接