【问题标题】:How to define NULL using #define如何使用#define 定义NULL
【发布时间】:2010-02-24 11:40:52
【问题描述】:

我想在我的程序中重新定义NULL比如

#define MYNULL ((void*)0)

但是这个定义在下面的语句中不起作用:

char *ch = MYNULL;

错误:无法从 void* 转换为 char *

定义 NULL 的最佳方法是什么?

【问题讨论】:

  • 哪种语言? C 或 C++,它们是非常不同的语言
  • 你认为你为什么需要这样做?
  • 您能否将变量 ch 的名称更改为其他名称(例如 str),因为这可能会使快速阅读它的人感到困惑,他们可能会推断您对 NUL 处理感兴趣。 (但我真正的问题是(正如@Neil Butterworth 所问的那样),为什么?)(或者你能澄清一下你希望达到的目标吗?你是否试图让一个清单常量同时作为指针和 NUL 字符具有双重职责?
  • 就目前而言,这只是一个糟糕的问题,因为您几乎肯定不应该这样做。也许如果你解释一下你的动机是什么,理由可能会更清楚?
  • 这是一个令人担忧的问题 - 表明做了坏事。

标签: c++ c null


【解决方案1】:
#define MYNULL NULL

是最安全的,我认为没有理由这样做,但如果您真的想这样做,请继续。 以下是 C 和 C++ 分别是如何做到的:

#define NULL 0 //C++
#define NULL ((void*)0) //C

一般来说,将 0 定义为 NULL 是一个坏习惯,您实际上希望它成为语言的一部分。 C++0x 解决了这个问题。

这就是 Bjarne Stroustrup 对say on this 的要求:

我应该使用 NULL 还是 0?

在C++中,NULL的定义是0,所以只是审美上的区别。我更喜欢避免使用宏,所以我使用 0。NULL 的另一个问题是人们有时会错误地认为它不同于 0 和/或不是整数。在准标准代码中,NULL 有时被/被定义为不合适的东西,因此必须/必须避免。现在这种情况不太常见了。

如果必须给空指针命名,就叫它nullptr;这就是它在 C++11 中的名称。然后,“nullptr”将成为关键字。

【讨论】:

    【解决方案2】:
    #ifdef __cplusplus
    #define MYNULL 0
    #else
    #define MYNULL ((void*)0)
    #endif
    

    两者都适用。

    【讨论】:

    • 问题是“如何在 C++ 和 C 中使用 #define 定义 NULL”,据我了解,这不是“如果我等到有人实现 c++0x 时如何处理 NULL好”,或者“是否有任何使用 NULL 的警告”。你为什么不只是假设 cppdev 知道他在做什么,只是想回答这个问题?这就是我讨厌stackoverflow的地方——通常我有使用我的解决方案的理由,并且不想要提示如何以其他方式做到这一点。 (好吧,这个问题没有前提假设)。使用你的魔法球和其他具有前瞻性的配饰来做一些更有趣的事情。
    • @Yossarian:一个好问题的一部分(值得许多赞成)是 FizzBin 和/或以其他方式确定您在决定用您的重要信息打扰 LazyWeb 的道路上已经尝试和未尝试做的事情问题)。并且不要担心成为这个星球上唯一一个被 SO 激怒的人,它有很多 + 和(不是那么多) - 点(在每个意义上):P 但是当我们分裂头发时,你真的认为那,与网站上的所有其他答案相比,这个唯一值得 96 代表? (不,我的回答不值 60 - 它是评论的重复)。去约翰内斯!
    • 我不介意 - 点,我只是不喜欢你的论点。
    • 给我一个 -1 的评论,并且有人愿意站在他们的观点上和/或解释为什么他们认为它在任何一天都超过 -1 是正确的。对于像这个问题这样的微妙问题,让暴民规则根据可能有缺陷的理解来解决问题,使用反对票来抵消基于不完全理解的支持票是不够的。我不得不说,与我看到的其他人相比,这个问题的标签上发生的这种废话要多得多。正如我所说,我们都讨厌 SO :(
    • 我回答了这个问题,被问者显然想要这个答案。你的答案是一堆假设,推测 c++0x,并假设有正确的标准库供平台 askee 开发。
    【解决方案3】:

    从你应该去的地方获取 NULL 到底有什么问题?即,

    #include <stddef.h>
    

     #include <cstddef>
    

    正如@Johannes Rudolph 的回答中提到的那样,面对nullptr 等事情,你所做的任何诡计都不太可能成为未来的证据。

    编辑:虽然 stdlib(和许多其他)被强制包含 NULL,但 stddef 是最规范的标头 [并且已经使用了数十年]。

    PS 一般来说,除非你有充分的理由,否则参与这种诡计是个坏主意。您没有扩展导致您感到需要这样做的想法。如果您可以对此添加一些细节,则可能会导致更好的答案。其他回答这个问题的人也应该在他们的回答中指出这一点,但我猜 FGITW 是 FGITW 做得最好的:D

    编辑 2:正如@Yossarian 所指出的:这样做的唯一理由是,如果系统中其他地方没有以适当的语言无关形式定义 NULL。没有头文件的裸编译器和/或如果您从头开始编写自己的自定义标准库,就是这种情况的示例。 (在这种简单的情况下,我会选择@lilburne 的答案(请务必尽可能使用0))

    【讨论】:

    • @legends2k:对我来说似乎很明显(以及@Neil Butterworth 在 cmets 中的问题,但在我之前没有人 +1),但我猜人们喜欢解决不需要解决的难题.
    • @Ruben:程序员,你看;)
    • @legends2k:你的意思是“黑客”!我猜人们不在这个网站上,因为他们相信地球上需要说的一切都已经说过了:P
    • @Ruben:好吧,“黑客”,但不是全部,他们中的很多人都是 :)
    • @-1er:愿意解释一下你的反对意见吗?如果您有理由认为这是一个错误的答案,那么全世界都可以从分享推理中受益。 (如果你愿意,我可以提供一堆关于神秘选民身份的猜测和假设!)
    【解决方案4】:
    #define MYNULL 0
    

    将在 C++ 中工作

    【讨论】:

    • 这仅适用于 C++。 C 需要将 NULL 定义为 (void *)0。
    • @Paul:将NULL 定义为0 在C 中可以正常工作,只是你失去了一点类型安全性。但是,在 C 中为 NULL 正确使用 0 不会产生任何错误。如果您要使用 varargs sentinel 值进行反驳,即使使用 NULL,也建议大小写为 char*
    • @Evan - 你是对的 - 我检查过了 - 谢谢你的纠正!
    【解决方案5】:

    不要这样做。 没有什么说 NULL 必须是零值,它是特定于实现的。

    它可能是一个表示内存结束的值,内存中的某个特殊位置,甚至是一个表示不存在值的对象。

    这样做非常危险,可能会破坏可移植性,并且肯定会与代码感知编辑器发生冲突。它不会给你买任何东西,相信你图书馆的定义。

    编辑:Evan 是正确的! 代码本身会说零,在引擎盖下,编译器可以用实现特定的细节做它想做的事。谢谢埃文!

    【讨论】:

    • 这是对标准的常见误解。空指针常量 0。但是空指针值(未在语言级别公开,因此您不必担心)可能是特定于机器的。 C99 标准 6.3.2.3:“值为 0 的整数常量表达式,或转换为 void * 类型的此类表达式称为空指针常量。55) 如果将空指针常量转换为指针类型,则生成的指针,称为空指针,保证与指向任何对象或函数的指针不相等。”这基本上说“在指针上下文中使用的 0 是 NULL。”
    • @Walt:没问题,我现在删除我的 -1 :-)。
    【解决方案6】:

    我认为任何不知道将 C/C++ 中的指针设置为 0 与将其设置为 NULL、nullptr 或任何其他等效项相同的人都不应该弄乱代码。

    char* ch = NULL
    

    char* ch = 0;
    

    是最小的。当涉及到表达式的形式时

    if (NULL == ch) {
    }
    if (0 == ch) {
    }
    if (nullptr == ch) {
    }
    

    可读性不比

    if (!ch) {
    }
    

    【讨论】:

    • @lilburne:将 nullptr 带入您的示例会使事情变得混乱,而不是澄清它们。 nullptr 有一个目的,并不总是 100% 可与 NULL 互换。但我同意一般观点,对于大多数用途,应该考虑更喜欢0 和隐式cooercion 而不是int 到NULL。 (但是当它把这些问题混为一谈时,它并没有得到我的 +1 :D)
    【解决方案7】:

    与这里有些人所说的相反,0 是 C 中 NULL 的完全有效定义。因此,当您将 NULL 作为参数提供给可变参数函数时必须小心,因为它可能被误认为是整数值0,以不可移植性结尾。

    http://c-faq.com/null/null2.html

    顺便说一句,comp.lang.c 常见问题解答是每个 C 程序员的强烈推荐阅读。例如,请参见此处:

    http://c-faq.com/null/null1.html

    包含诸如“如上所述,每种指针类型都有一个空指针,不同类型的空指针的内部值可能不同”这样的几乎被遗忘的智慧。这意味着 calloc 或 memset 不是指针的可移植初始化。

    【讨论】:

      【解决方案8】:
      #define NULL 0 //for C
      

      是C语言中的完美定义

      例如

      char *ch = NULL ;
      *ch++ ;// will cause error
      

      它会导致错误,因为 ch 在执行增量语句时指向任何内容 编译器通过查看 LOOK-UP 表中指针的值为 0 就知道了

      如果你尝试更新这个指针,那么你实际上是在改变 从 0 物理地址开始的 CODE 区域。 因此,代码区域之前的页表的第一个条目开始 保持为空

      从你应该去的地方获取 NULL 到底有什么问题?即,

      #include <stddef.h>
      

      #include <cstddef>
      

      正如@Johannes Rudolph 的回答中提到的那样,面对 nullptr 等问题,您所做的任何诡计都不太可能成为未来的证据。

      编辑:虽然 stdlib(和许多其他)被强制包含一个 NULL,但 stddef 是最规范的标头 [并且已经使用了几十年]。

      PS 一般来说,除非你有充分的理由,否则参与这种诡计是个坏主意。您没有扩展导致您感到需要这样做的想法。如果您可以对此添加一些细节,则可能会导致更好的答案。其他回答这个问题的人也应该在他们的回答中指出这一点,但我猜 FGITW 是 FGITW 做得最好的:D

      编辑 2:正如@Yossarian 所指出的:这样做的唯一理由是,如果系统中其他地方没有以适当的语言无关形式定义 NULL。没有头文件的裸编译器和/或如果您从头开始编写自己的自定义标准库,就是这种情况的示例。 (在这种简单的场景中,我会选择@lilburne 的答案(一定要尽可能使用 0))

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多