【问题标题】:NULL vs Zero in CC中的NULL与零
【发布时间】:2020-07-15 23:00:30
【问题描述】:

我最近看了Can I use NULL as substitution for the value of 0?

简而言之,在答案中提到,不建议使用 NULL 代替 0 的值,这会导致 UB。

但在Is it safe to assume that the NULL constant is zero? 中,总之有人说假设if(!ptr)//ptr is a pointer 并不完全错误。

我知道问题的内容不同,但是如何解释使用 NULL 代替 0 是错误的,而 if(!ptr) 是正确的? 因为if(!ptr) 等价于if(ptr==0)(我认为这是对的,不确定)。

另外,我使用了if(ptr==0),它对我来说从来没有错(检查ptr 是否为NULL),并且我已经0 分配给指针ptr 以及何时我调试了我的代码 ptr 为 NULL。这两种体验安全吗?

【问题讨论】:

    标签: c null null-pointer


    【解决方案1】:

    来自this NULL pointer reference

    要将指针初始化为空或将空值分配给现有指针,可以使用空指针常量(NULL,或任何其他值为 0 的整数常量)。

    [强调我的]

    所以整数常量0是一个有效的空指针常量。

    但请注意,这并不意味着所使用的硬件平台上的实际空值等于0,它仅意味着编译器接受0 作为系统相关空指针常量的别名。

    此外,空指针始终为“假”,非空指针始终为“真”,这就是if (ptr)if (!ptr) 之类的条件适用的原因。

    【讨论】:

      【解决方案2】:

      我知道问题内容不同,但怎么会这样 解释了使用 NULL 代替 0 是错误的,而 if(!ptr) 是真的吗?因为if(!ptr) 等价于if(ptr==0)(我 假设这是正确的,不确定)。

      if(!ptr) 根据if 语句的语义等价于if (!ptr != 0),根据!!=== 运算符的语义和指针操作数等价于if (ptr == 0)。这是非常一致的,但它并没有从您对整数运算的任何了解中得出。对指针的操作有自己的一套规则。

      这正是我们的收获。因为一个值为 0 的整数常量——它是一个 源代码 构造——除其他外,它是一个空指针常量,它根据定义比较等于所有 null指针值。这完全没有说明任何类型的空指针值的表示,关于 NULL 宏扩展的表达式的类型,或者关于通过将任何特定的空指针值转换为整数而产生的值源代码为一个值为零的整数常量。

      【讨论】:

        【解决方案3】:

        NULL 是一个宏。它是一个“实现定义的空指针常量”; C17dr § 7.19 3.

        值为 0 的整数常量表达式,或转换为 void * 类型的此类表达式称为 空指针常量。 C17dr § 6.3.2.3 3

        所以NULL 可能有void *intlongunsignedlong long 等类型。

        0 是一个int 常量。

        一切正常。

        赋值:下面都将p,q 赋值给一些空指针

        void *p = 0;
        void *q = NULL; 
        

        代码比较p==q 为真,因为所有 空指针 都相等。所有空指针都不等同于任何对象的地址。 !p!q 都是 1。

        当它不正常时。

        函数参数

        NULL 的类型及其大小由实现定义。

        printf("%d\n", 0);            // OK - %d expects an int
        printf("%d\n", NULL);         // Not OK, NULL could be long, void *, etc.
        printf("%p\n", NULL);         // Not OK, NULL could be int, long, long long
        printf("%p\n", (void*) NULL); // OK - %p expects a void*
        

        _Generic()

        下面的结果是实现定义的。

        _Generic((NULL), \
          void *: "void *", \
          int: "int", \
          long: "long", \
          default: "TBD")
        

        宏观比较

        对我来说,以下导致“错误:运算符'*'没有正确的操作数”。 #if !0 很好。

        #if !NULL
        #error foo
        #endif
        

        【讨论】:

        • 这是ptr=0 好吗?我的意思是,这个初始化而不是ptr=NULL right 可以使用吗?
        • 实现可能会或可能不会保证所有printf 示例的任何内容,但是那些指定以某些方式定义NULL 的实现将需要处理第二个或第三个“不正常” " 以有意义的方式行,具体取决于他们指定 NULL 的精确程度。
        • 先把int0转换成一个指针,一个空指针然后赋值。定义良好。第二个将NULL 的任何类型转换为指针,即 null 指针,然后分配。也很好定义。使用任何一种,最好按照您小组的编码标准/风格进行编码。
        • @supercat "实现可能会或可能不会保证所有 printf 示例的任何内容," --> printf("%d\n", 0); 不能保证什么?
        • @chux-ReinstateMonica:他们将被要求提供关于一些,但不是全部的保证。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-11
        • 2010-10-08
        • 1970-01-01
        • 2020-07-31
        • 2021-10-01
        • 2014-04-28
        • 1970-01-01
        相关资源
        最近更新 更多