三个问题: NULL - NULL 定义了吗? (uintptr_t)NULL - (uintptr_t)NULL 定义了吗? [复制]

Posted

技术标签:

【中文标题】三个问题: NULL - NULL 定义了吗? (uintptr_t)NULL - (uintptr_t)NULL 定义了吗? [复制]【英文标题】:Three questions: Is NULL - NULL defined? Is (uintptr_t)NULL - (uintptr_t)NULL defined? [duplicate] 【发布时间】:2021-02-20 15:17:52 【问题描述】:

1.NULL - NULL 定义了吗?

    (char *)NULL - (char *)NULL 定义了吗?

    (uintptr_t)NULL - (uintptr_t)NULL 定义了吗?

我知道它适用于我使用的所有实现。但是从标准的角度来看它是什么样子的呢?我找不到明确的答案。

编辑: 从欺骗我假设问题的一个答案是:是的。

第二个和第三个问题呢?

【问题讨论】:

C 标准文档NULL 被定义为一个宏扩展为实现定义的空指针常量 根据实际定义,表达式NULL - NULL 可能有或没有定义的值。例如:* 如果NULL 定义为#define NULL 0,那么NULL - NULL 实际上是一个int 类型的常量表达式,其值为0。 * 如果NULL 定义为#define NULL ((void *)0),则表达式NULL - NULL 是违反约束的,因为没有在void 指针上定义算术。 不是我,但我会添加答案中提到的内容:C18 §6.5.6.9 声明 “当减去两个指针时,两个指针都应指向指向同一个数组对象的元素,或数组对象的最后一个元素;结果是两个数组元素的下标的差异。" 但是NULL 值不指向任何对象, 并将其转换为另一种指针类型不会改变这一点。 投票是匿名的,这是有充分理由的。不知道为什么会有DV。 对不起,你得在 Meta 上问。 @curiousguy:我没有投反对票,但投反对票按钮的工具提示说(除其他外)“没有显示任何研究工作”。如果问题是明显重复的,那么这是拒绝投票的正当理由。此外,否决票是有意匿名的,完全取决于选民。 【参考方案1】:

C 标准文档 NULL 被定义为宏扩展为实现定义的空指针常量

根据实际定义,表达式NULL - NULL 可能有定义值,也可能没有定义值。例如:

如果NULL被定义为#define NULL 0,那么NULL - NULL实际上是一个int类型的常量表达式,其值为0。 如果 NULL 定义为 #define NULL ((void *)0),则表达式 NULL 是违反约束的,因为算术未在 void 指针上定义。

第二个问题:是否定义了(char*)NULL - (char*)NULL(uintptr_t)NULL - (uintptr_t)NULL。这些表达式不再违反约束:

由于从void * 到算术类型的转换是实现定义的,所以不能说(uintptr_t)NULL - (uintptr_t)NULL 的值。在大多数当前系统上它将是 0,但 C 标准没有定义它。

转换为(char *) 是一个稍微不同的事情:2 个指针的差异仅在它们指向同一个数组或数组最后一个元素之后的位置时才定义,一个对象被认为是一个元素的数组对于这个讨论。 (char *)NULL 不是这种情况,它是一个空指针,因此不指向任何数组或对象。

【讨论】:

是的,我知道它在大多数实现中是如何工作的。我已经编辑了这个问题,添加了两个额外的案例。 @P__JsupportswomeninPoland,这样改变问题的性质对事先回答的chqrlie有点不公平。 @Elliott 我添加了两个额外的问题。 chqrlie 答案与更改前一样好。我认为您误解了不改变问题的想法。 @P__JsupportswomeninPoland:关于“我在 C 标准中没有看到任何内容表明两个相同的语句可以给出不同的结果”:如果声明不是未指定,则未指定某些内容。只有在某处有肯定的陈述时才指定它。 void * 可能有填充位,例如,如果实现使用 48 位地址空间但使用 64 位作为指针并忽略高 16 位。尽管(void *) 0 不太可能发生这种情况,但转换为指针类型可能只是设置低 48 位并获取发生的任何内容…… ... 位于高 16 位。所以void *a = &x, *b = &x; 可能会导致ab 中的不同位,即使它们指向同一事物并且比较相等。到uintptr_t 的转换可能被定义为包括所有 64 位,即使 16 位与地址无关。所以(uintptr_t) a 可能不等于(uintptr_t) b。由此,我们看到 C 标准允许(uintptr_t) (void *) 0 == (uintptr_t) (void *) 0 可能为假,即使不太可能。

以上是关于三个问题: NULL - NULL 定义了吗? (uintptr_t)NULL - (uintptr_t)NULL 定义了吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

C语言 | 每日基础(23)

C#变量定义中含问号代表啥

DialogFragment.getDialog 返回 null

Mongoose 为 Number 字段接受 null

ElasticSearch NEST API 更新值为 null

findFragmentByTag() 在使用 replace() 方法执行 FragmentTransaction 后返回 null