当前位置: 首页 > 知识库问答 >
问题:

((void*)0)是否为空指针常量?

艾骏
2023-03-14

我正在读这篇博文,在空指针常量和括号表达式一节中,作者引用了ISO C标准中的6.3.2.3和6.5.1,他说:

它并不是说带括号的空指针常量是空指针常量。

这意味着,严格来说,(void*)0是一个空指针常量,但((void*)0)不是。

然后:

我确信大多数C实现确实将带括号的空指针常量视为空指针常量,并将NULL定义为0((void*)0)或以其他方式。

引用的两个部分说:

6.3.2.3

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

6.5.1

带括号的表达式是主表达式。它的类型和值与非参数化表达式的类型和值相同。如果非粘性表达式分别是左值、函数指示符或空表达式,则它是左值、函数指示符或空表达式。

加粗的句子是否与作者的说法相矛盾,即((void*)0)不是空指针常量?

共有3个答案

魏英勋
2023-03-14

尝试打印C代码下面的行:

打印f("%p",(无效*)0);

您将得到如下输出:

(无)

谢同化
2023-03-14

它是一个带括号的表达式,包含一个空指针常量,因此它无疑是一个空指针值。将它用作右值与将“兼容”版本用作r值具有完全相同的效果。

如果有一些语法规则只能接受空指针常量,那么它就不合格。但我不知道有什么(尽管我对C语言不太精通)。

虽然两者都不是常量(指形式语法产生),但两者都可以出现在初始化程序中的常量表达式中,因为空指针常量和地址常量都是允许的,并且常量空指针值明确包含在地址常量类别中。

指针比较还特别提到了空指针常量...但是这里也接受指针值,所有空指针值都被同等对待。三元运算符和赋值运算符也是如此。

请注意,这些规则在C中有很大不同,其中上述两个表达式都是void*类型的常量空指针值,但不是通用空指针常量。C中的空指针常量是求值为零的整型常量表达式。void*不会隐式转换为其他指针类型。

拓拔弘化
2023-03-14

加粗的句子是否与作者的说法相矛盾,即((void*)0)不是空指针常量?

不,它没有。(我承认有点偏见,因为引用的博客是我的。

粗体句子表示其类型和值与未解析表达式的类型和值相同。这还不足以暗示它是一个空指针常量。

考虑:

void *var = 0;

(void*)0是一个空指针常量。((void*)0)(void*)0具有相同的类型和值。var也与(void*)0具有相同的类型和值,但var显然不是空指针常量。

话虽如此,我99%确定意图是((void*)0)是空指针常量,更一般地说,任何括号中的空指针常量都是空指针常量。该标准的作者只是忽略了这一点。由于 6.5.1p5 中括号表达式的描述专门枚举了由括号表达式继承的其他几个特征:

带括号的表达式是主表达式。它的类型和值与非参数化表达式的类型和值相同。如果非粘性表达式分别是左值、函数指示符或空表达式,则它是左值、函数指示符或空表达式。

遗漏令人不安(但只是轻微的)。

但为了便于讨论,我们假设((void*)0)不是空指针常量。这有什么区别?

(void*)0是一个空指针常量,它的值是一个类型为void*的空指针,所以通过带括号表达式的语义学((void*)0)也有一个值是一个类型为void*的空指针。(void*)0((void*)0)都是地址常量。(嗯,我认为它们是。)那么哪些上下文需要空指针常量并且不接受地址常量呢?只有少数。

函数指针类型的表达式可以与空指针常量进行比较。(对象指针可以比作< code>void*类型的表达式,但函数指针不可以,除非它是空指针常量。)所以这个:

void func(void);
if (func == ((void*)0)) { /* ... */ }

将违反约束。

在赋值中,可以将空指针常量分配给指向函数类型的对象,并将进行隐式转换。不是空指针常量的 void* 类型的表达式可能不会分配给函数指针。同样的约束也适用于参数传递和初始化。所以这个:

void (*fp)(void) = ((void*)0);

如果< code>((void*)0)不是空指针常量,将违反约束。感谢评论者hvd找到这个。

NULL扩展为“实现定义的空指针常量”。如果((void*)0)不是空指针常量,则如下:

#define NULL ((void*)0)

将无效。这将是对实现的限制,而不是对程序员的限制。请注意:

#define NULL (void*)0

肯定是无效的,因为标准头中的宏定义必须在必要的地方用括号完全保护起来(7.1.2p5)。如果没有括号,有效的表达式< code>sizeof NULL将是一个语法错误,扩展为< code>sizeof (void*)后跟一个无关的常量< code>0。

 类似资料:
  • void与空类型指针 空类型的指针可以存储任何类型变量(普通变量,一级指针变量,二级指针变量,三级指针变量,多级指针变量等等...)的地址,因为编译器决定了地址存储尺寸 空类型的指针既不可以间接取值,也不可以间接赋值(也就是只能存储内存地址,而不能根据内存地址进行间接访问操作) 将空类型的指针转化为具体指针类型,然后就达到了既明确了指针的解析步长,也明确了解析方式 ///01.void.c #in

  • 我在尝试单元测试函数调用时遇到了一个问题。尽管调用已被存根,但由于无效方法调用而失败。 请在下面找到我的代码的简化快照。我正在使用do答案()存根来模拟空方法(基于StackOverflow上的早期答案)。 我甚至尝试了其他选项的和存根,但当调用存根方法时,它们也会在相同的NPE中失败:(。 如果有人能提出解决方案/解决方法,我将不胜感激。非常感谢。 考试班 正在测试的实现类,来自该类的存根方法调

  • 问题内容: 有可能这可能是一个双重问题。我将String变量初始化为null。我可能会或可能不会使用一个值更新它。现在我想检查此变量是否不等于null以及我尝试执行的操作是否会得到null指针异常。空指针异常,因为它代价高昂。是否有任何有效的解决方法.TIA 问题答案: 如果您使用 你 不会 得到。 我怀疑你在做什么: 这是因为null 而引发,而不是因为null。 如果仍然无法解释,请发布您用于

  • 我已经更新了我的项目中的一些依赖关系之后,我的Hibernate配置类显示Nullpointerx的。 我将SpringDataJPA存储库与hibernate一起使用,已经超过24小时了,仍然没有找到任何关于小问题的适当解决方案。 我已经尝试过的一些解决方案:- 使用@bean(name=“entityManagerFactory”)提供bean名称 我面临的问题 波姆。xml文件 配置类 db

  • 当我试图从DB查询结果时,我得到一个空指针异常。以下是错误: 这是错误产生的函数。 如果我启动应用程序信息服务(=new ApplicationInfoService()),我会得到一个指向我的服务类的空指针错误,在这里进行查询 错误转到createQuery行,如果我打印出EntityManager,它将返回“null”。为什么我的Entitymanager不能初始化。我在我的登录系统中使用了几

  • 我在当前版本的Java8中发现了一个奇怪的行为。在我看来,下面的代码应该可以,但是JVM抛出了一个: 这并不重要,它是什么样的lambda表达式(与相同)或使用了什么泛型类型。也可以用更有意义的表达式来代替。上面的例子很短。这里有一个更丰富多彩的例子: 然而,这些代码段运行良好: 和 或与功能: 我测试了两个Java版本: openjdk版本“1.8.0_66-internal”openjdk运行