【问题标题】:How do you deal with NUL?你如何处理 NUL?
【发布时间】:2010-09-18 05:42:45
【问题描述】:

有时,当我们谈论 NULL 时,我会遇到与其他程序员的沟通问题。现在 NULL 可能是

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


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


你更喜欢用什么来做 NUL?为什么?

【问题讨论】:

  • \0 是 NUL,而不是 NULL。因此,我恢复到 OP 的原始版本。
  • 您的问题是关于对话的清晰性还是代码的清晰性?请澄清。
  • 两者都是。从口头上讲,设置上下文并没有太大作用。在代码中,我更喜欢避免由隐式转换引起的额外代码。我有兴趣了解其他开发人员如何处理这个问题,或者至少获得一些其他关于如何思考它的观点。
  • 每一行的意图是什么? char x = NULL;
    char *x = NULL;
    char *x = 0;
    char x = 0;
    char *x = '\0';
    char x = ' \0';
  • 它们都存储了相同的二进制模式,但意图并不明确。 NULL 有指针的含义,0 有整数的含义,而 '\0' 更接近于 NUL。

标签: c++ c


【解决方案1】:

我将'\0' 用于空字符,NULL 用于指针,因为在这两种情况下都是最清晰的。

顺便说一句,0 和 '\0' 在 C 中都是 ints,当存储在 char 变量中时,任何一个都将转换为 char。

【讨论】:

  • 嗯。我的印象是单引号中的字符是 c 中的字符。
  • 在 C++ 中,具有单个字符的字符常量是 char 类型,在 C 中,字符常量是 int 类型。
  • 0 在 C 中是 not int。它是一个特殊的整数文字,没有这样的类型,但可以在 int 或指针上下文中使用(很像 C# null)。
  • @Pavel: 0 is C 中的一个 int 值,它和其他任何值一样是一个常规整数值。当文字 0 转换为指针时,结果是空指针,因此 0 或 (void *)0 被称为空指针常量,但这并没有改变在将其转换为指针之前 0 是整数的事实将其转换为指针后,它不再是整数而是空指针。您可能需要查看 c-faq 的第 5 部分 (c-faq.com/null/index.html)。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    有许多英语单词拼写或口语相似,但含义不同。就像在英语中一样,使用讨论发生的上下文来引导你理解预期的意思。

    【讨论】:

      【解决方案4】:
      • 为了处理字符串,我总是将空字符表示为'\0'。
      • 对于指针,我尝试使用隐式转换为布尔值(if (!myPtr) 或 if (myPtr))来保证指针为空。
      • 如果我需要一个指针的默认值,它是 NULL,例如结构 list_head = { 0.0, NULL };)。

      END_OF_STRING 很愚蠢,因为它是一种额外的间接方式,只会让新读者感到困惑(任何不能立即识别 '\0' 的人都应该离开键盘)。

      另一件事——我认为在谈论数据建模时,空值和空值之间的区别非常重要。在讨论 C 风格的字符串或可为空的数据库字段时尤其如此。有人告诉你“我没有名字”和“我的名字是……”之间存在巨大差异。

      【讨论】:

      • 为了提高清晰度,我通常在 if 语句中使用赋值语句时显式检查 NULL: if ((myPtr = GetData()) != NULL) { /* do work on myPtr */ }
      【解决方案5】:

      @BKB:

      我在他的建议中看到了要点,但是“NULL”更清楚地表明上下文是指针。就像在处理字符时使用“0.0”来表示浮点值一样,就像“\0”一样。 (同样,如果在算术上下文中使用 char,我更喜欢看到 0。)

      Bjarne 在this FAQ 中进一步指出,NULL 无论如何都#defined 为 0,因此标准代码不应该有问题。我同意全大写表示法很难看,但我们必须等到 0x (这里可以使用 nullptr 作为关键字。)

      【讨论】:

        【解决方案6】:

        如果我没记错的话,大多数 C 编译器都这样定义 NULL:

        #define NULL ((void*)0)
        

        这是为了确保 NULL 被解释为指针类型(在 C 中)。然而,这可能会在 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++ 编译器在将托管指针设置为空时也使用此关键字。在当前的编译器中,您可以创建一个模板来模拟这个新关键字。

        wikibooks.org 上有一篇更详细的文章讨论了这个问题。

        【讨论】:

        • NULL 和 0 在 C++ 中是等价的。您可以使用 NULL 来初始化两种语言中的指针而不会出现问题。任何以旧 C 风格定义 NULL 的 C++ 库都是不合格的。
        【解决方案7】:
        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.)
        

        【讨论】:

          【解决方案8】:

          数据库为NULL,代码为NIL。

          【讨论】:

            【解决方案9】:

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

            #define NULL 0
            #define END_OF_STRING '\0'
            

            与定义一样有意义:

            #define SEVEN 7
            

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

            【讨论】:

            • 我看到的不同之处在于“7”是一个始终表示“七”的符号(至少作为 C 标记)。 '\0' 当然用作字符串终止符,但这并不总是和固有的 0 字节的含义,因此它不是字符串结尾的同义词,超过 200 是成功的同义词。
            • 也就是说,我认为使用 '\0' 作为文字没有任何问题,只是因为它有时也用于其他事情。但我也不认为使用名称是没有意义的,因为即使在所有 C 程序中字符串结尾的值当然都是 0,也会存在语义差异。
            • 我想我在这里想的 C++ 比 C 多。 \0 仅适用于以空字符结尾的字符串。所以我认为它比 END_OF_STRING 清楚得多,它实际上可能不是字符串结尾。 END_OF_NULL_TERMINATED_STRING 做得太过分了。
            • 真的是 Gorpik :) 那不是 END_OF_NUL_TERMINATED_STRING 吗?
            【解决方案10】:

            很喜欢

            #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 得到一些有用的警告或错误。

            【讨论】:

              【解决方案11】:

              对于通信,我使用 NULL。如果我正在与无法掌握不同数据类型的 NULL 概念的开发人员合作,那么我会担心。

              对于实施,它是特定于案例的。数字为 0(浮点数后置 f),指针为 NULL,字符串为 0。

              【讨论】:

                【解决方案12】:

                不使用二进制 0 表示 NULL 的系统越来越难找到。它们还往往存在各种可移植性问题。为什么?因为在这些系统上,memset 和 calloc 都不能正确清除包含指针的结构。

                【讨论】:

                • 我当然从未见过不等于零的 NULL。
                【解决方案13】:
                const char END_OF_STRING = '\0';
                

                所以当你说:

                str[i] = END_OF_STRING;
                

                或

                if (*ptr == END_OF_STRING)
                

                你的意思绝对没有问题。

                【讨论】:

                  【解决方案14】:

                  我们使用 NULL 表示指针,使用 NULLCHAR 表示字符,使用

                  #define NULLCHAR '\0'
                  

                  【讨论】:

                    【解决方案15】:

                    有点相关:Slashdot 最近在comp.lang.c FAQ section on null pointers 上有一个故事,我觉得很有趣。

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2010-10-29
                      • 2012-10-04
                      • 1970-01-01
                      • 1970-01-01
                      • 2012-06-15
                      • 1970-01-01
                      • 2013-09-25
                      相关资源
                      最近更新 更多