如何处理NUL?

5

有时候,我与其他程序员交流时,会遇到关于NULL的沟通问题。现在NULL可能是:

一个NULL指针
NUL字符
某种数据库中的空数据元素。


NUL似乎最令人困惑。它是ASCII字符0x00。
我倾向于在我的代码中使用'\0'来表示它。我的一些同事倾向于只使用0,并让编译器隐式地将其转换为char。


你更喜欢使用哪个来代表NUL?为什么?


\0代表NUL,不是NULL。因此,我还原了原始修订版。 - C. K. Young
1
你的问题是关于对话的清晰度还是代码的清晰度?请澄清。 - mxcl
这是两者兼备的。口头上,它并不能很好地设置上下文。在代码中,我更喜欢避免由隐式转换引起的额外代码。我很想看看其他开发人员如何处理这个问题,或者至少获得一些其他观点来思考它。 - EvilTeach
这些行的意图是什么?char x = NULL;<br> char *x = NULL;<br> char *x = 0;<br> char x = 0;<br> char *x = '\0';<br> char x = '\0';<br> - EvilTeach
它们都以相同的漂亮二进制模式进行排序,但意图并不清楚。NULL具有指针的含义,而0具有整数的含义,而'\0'更接近于NUL。 - EvilTeach
15个回答

10

我在表示空字符时使用'\0',在指针方面则使用NULL,因为在两种情况下都很清晰。

顺便提一下,在C语言中,0'\0'都是int类型的,当存储在char变量中时会被转换为char


我曾认为在单引号中的字符是C语言中的char类型。 - EvilTeach
在C++中,只有一个字符的字符常量的类型是char,在C中,字符常量的类型是int。 - Robert Gamble
在C语言中,0不是int类型。它是一个特殊的整数字面量,没有具体的类型,但可以在int或指针上下文中使用(就像C#中的null一样)。 - Pavel Minaev
@Pavel:在C语言中,0是一个整数,就像任何其他常规整数值一样。当将字面量0转换为指针时,结果是一个空指针,因此0或(void *) 0被称为空指针常量,但这并不改变在将其转换为指针之前它是一个整数的事实,在将其转换为指针之后,它不再是一个整数,而是一个空指针。您可能需要查看c-faq的第5节(http://c-faq.com/null/index.html)。 - Robert Gamble

5

我喜欢预定义的NULL宏,因为它保留了语义意义,而不是使用数字0的其他用法。


4

有许多英文单词的拼写或发音相同,但意义不同。与英语类似,使用讨论所在的上下文来指导您找到预期的含义。


4
  • 在处理字符串时,我总是将空字符表示为'\0'。
  • 对于指针,我尝试使用隐式转换到布尔值(如果(!myPtr)或if(myPtr))来判断指针是否为空。
  • 如果需要指针的默认值,则为NULL,例如结构体list_head = { 0.0,NULL };)。

END_OF_STRING很傻,因为这只会使新读者感到困惑(任何不立即认识'\0'的人都应该离开键盘)。

还有一件事——我认为在讨论数据建模时,null值和空值之间的区别非常重要。特别是在讨论C风格的字符串或可空数据库字段时。当有人告诉你“我没有名字”和“我的名字是 ”之间有很大的差异。


1
为了增加清晰度,我通常在使用赋值语句时明确检查NULL,例如在if语句中:if ((myPtr = GetData()) != NULL) { /* 对myPtr进行操作 */ } - Isak Savo

3
A one-L NUL, it ends a string. 
A two-L NULL points to no thing. 
And I will bet a golden bull 
That there is no three-L NULLL. 



(The name of the original author is, alas, lost to the sands of time.)

3

如果我记得正确,大多数C编译器将NULL定义为以下内容:

#define NULL ((void*)0)

这是为了确保在 C 语言中将 NULL 解释为指针类型。然而,在 C++ 的类型严格的世界中,这可能会导致问题。例如:
// Example taken from wikibooks.org
std::string * str = NULL; // Can't automatically cast void * to std::string *
void (C::*pmf) () = &C::func;
if (pmf == NULL) {} // Can't automatically cast from void * to pointer to member function.

因此,在当前的C++标准中,空指针应该使用文字0进行初始化。显然,由于人们习惯使用NULL定义,我认为许多C++编译器要么默默地忽略这个问题,要么在C++代码中重新定义NULL为0。例如:
#ifdef __cplusplus
#define NULL (0)
#else
#define NULL ((void*)0)
#endif

C++x0标准现在定义了一个nullptr关键字来表示空指针。Visual C++ 2005的CLI/C++编译器在将托管指针设置为null时也使用此关键字。在当前的编译器中,您可以创建一个模板来模拟这个新关键字。
有一篇更详细的文章wikibooks.org讨论了这个问题。

在C++中,NULL和0是等价的。您可以使用NULL来初始化指针,在两种语言中都没有问题。任何定义了旧C风格中的NULL的C++库都是不符合规范的。 - Dan Olson

3

@BKB:

我理解他的建议,但是使用"NULL"可以更清晰地表明上下文是指针。就像在处理字符时使用'\0',浮点数值时使用"0.0"一样。(同样地,如果char在算术上下文中使用,我更喜欢看到0。)

Bjarne在这篇FAQ中进一步说明了NULL已经被定义为0,因此标准代码不应该有问题。我同意全大写符号的表示法很丑陋,但我们必须等到0x (nullptr将作为关键字可用)。


1

我相当喜欢

#define ASCII_NUL ('\0')

我很少将 '\0' 打错成 '0'。但是当我犯了这个错误时,通过代码检查很难发现错误,结果非常滑稽。所以我不太喜欢 '\0',更喜欢 ASCII_NUL 或 0(当然后者在 C++ 中类型错误)。显然,我会在需要与现有代码或样式指南保持一致的情况下使用 '\0'。

Google C++ 样式指南包含一些我喜欢和一些我不喜欢的东西,但似乎大多数都很合理,它更喜欢用 NULL 代替 0 来表示指针。它指出,在某些实现中,NULL 可能不仅仅被定义为 0(或 0L),特别是在 sizeof(void*) 可能不等于 sizeof(int)(或 sizeof(long int))的情况下。

0 和 NULL 都被指定为整数类型,并且当转换为指针类型时,它们都必须产生空指针值。但它们不一定是相同的整数类型。因此,在某些情况下,使用 NULL 可能会得到一些有用的警告或错误提示。


1

虽然总体上我建议使用命名常量,但这里有一个例外。对我来说,定义:

#define NULL 0
#define END_OF_STRING '\0'

这句话的意思就像定义:

#define SEVEN 7

没有。是的,我知道编译器已经定义了NULL,但我从不使用它。对于指针,用0;对于字符,用'\0'。更长并不总是意味着更具表现力。


我认为它们的区别在于,“7”是一个符号,它总是表示“七”(至少作为C令牌)。'\0'当然用作字符串终止符,但这并不总是和固有地意味着0字节就意味着字符串结束,所以它不等同于字符串结尾,就像200不等同于成功一样。 - Steve Jessop
话虽如此,我认为使用 '\0' 作为字面值并没有什么问题,因为它有时也用于其他事情。但是,即使所有 C 程序中字符串末尾的值当然都是 0,我也不认为使用名称是无意义的,因为存在语义上的区别。 - Steve Jessop
我想我在这里更多地考虑了C++而不是C。 \0仅用于以null结尾的字符串的字符串结束符。因此,我认为它比END_OF_STRING要清晰得多,后者实际上可能并不是字符串的结尾。而END_OF_NULL_TERMINATED_STRING则有些过头了。 - Gorpik
真的 Gorpik :) 那不应该是 END_OF_NUL_TERMINATED_STRING 吗? - EvilTeach

1

数据库用NULL,代码用NIL。


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