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

根据标准,取消引用等于 nullptr 的指针是否未定义行为?

经嘉
2023-03-14

一位博客作者提出了关于空指针解引用的讨论:

  • http://www.viva64.com/en/b/0306/

我在这里提出了一些反驳意见:

  • http://bit.ly/1L98GL4

他引用标准的主要推理是这样的:

的”

C99标准说了以下关于”

一元的操作数

表达'podhd-

如果将空指针常量转换为指针类型,那么得到的指针(称为空指针)肯定不等于指向任何对象或函数的指针。

当“左值在计算时不指定对象时,行为是未定义的”(C996.3.2.1“左值、数组和函数指示符”):

左值是具有对象类型或不完整类型的表达式,而不是void;如果左值在计算时没有指定对象,则行为未定义。

所以,同样的想法简而言之:

何时-

这个问题纯粹是基于语言的,我不是问一个给定的系统是否允许一个人篡改任何语言中地址0的内容。

据我所知,取消引用值等于nullptr的指针变量没有任何限制,即使考虑到指针与nullptr[或 nullptr的指针的引用。请注意,我已经检查了其他SO问题和答案,我特别喜欢这组引语,以及上面的标准引语,并且我没有偶然发现一些从标准中明确推断的东西,即如果指针 ptrnullptr比较,则取消引用将是未定义的行为。

我得到的最多是参考常量(或将其转换为任何指针类型)就是UB,但没有说明变量的位等于来自nullptr的值。

我想清楚地将< code>nullptr常量与包含一个等于它的值的指针变量分开。但是解决这两种情况答案是理想的。

我确实意识到,当与nullptr等进行比较时,优化可以快速进行,并且可以简单地基于此剥离代码。

如果结论是,如果ptr等于nullptr取消引用的值,那么它肯定是UB,另一个问题如下:

C和C标准是否意味着地址空间中必须存在一个特殊值来表示空指针的值?

共有3个答案

麻书
2023-03-14

我看到的答案是,关于 NULL 值可能被取消引用的程度,由于 C11 6.3.2.3p5 和 p6 中保留的实现定义,它被故意以未指定的方式与平台相关。这主要是为了支持用于为平台开发引导代码的独立实现,正如OP在他的反驳链接中指出的那样,但也有托管实现的应用程序。

回复:
(C11, 6.5.3.2p4) “如果为指针分配了无效值,则一元 * 运算符的行为未定义。

102):“一元*运算符取消引用指针的无效值包括空指针、针对指向的对象类型不正确对齐的地址以及对象生命周期结束后的地址。”

这是按原样表达的,因为脚注中的每个情况对于编译器所针对的特定平台可能并不无效。如果存在缺陷,则“无效值”应为斜体,并由“实现定义”限定。对于对齐情况,平台可以使用任何地址访问任何类型,因此没有对齐要求,尤其是在支持地址翻转的情况下;平台可以假设对象的生存期仅在应用程序退出后结束,通过malloc()为每个函数调用的自动变量分配一个新帧。

对于空指针,在引导时,平台可能期望处理器使用的结构具有特定的物理地址(包括地址 0),并在源代码中表示为对象指针,或者可能需要定义引导过程的函数使用基址 0。如果标准不允许取消引用,例如”

标准称之为指针的是虚拟机虚拟地址空间中的更多句柄,其中对象句柄对其允许的操作有更多要求。编译器如何发出将这些句柄的要求考虑到特定处理器的代码是未定义的。毕竟,对一个处理器有效的东西可能对另一个处理器无效。

对(void *)0的要求更多的是编译器发出代码,保证在源使用(void *)0的地方,显式地或通过引用NULL,存储的实际值将是一个不能通过任何映射代码指向任何有效函数定义或对象的值。这不一定是0!类似地,对于从(void *)0到(obj_type)和(func_type)的强制转换,只需要获得赋值,这些赋值评估为编译器保证不用于对象或代码的地址。后者的不同之处在于它们是未使用的,而不是无效的,因此能够以定义的方式取消引用。< br >

然后,测试指针相等性的代码将检查一个操作数是否是这些值中的一个,另一个是否是3个值中的一个,而不仅仅是相同的位模式,因为这将RTTI标记为(空*)类型,不同于用于定义实体的void、obj和func指针类型。标准可以更明确,如果未命名,它是一个不同的类型,因为编译器只在内部使用它,但我想这被斜体的“空指针”认为是显而易见的。实际上,在这些上下文中,“0”是编译器的附加关键字标记,因为它需要识别(null*)类型,但不是这样描述的,因为这会使

例如,当实现将虚拟机句柄的范围0到SIZE_MAX-4*sizeof(void*)定义为对代码和数据有效时,这个存储的值可以很容易地在发出的应用程序代码中SIZE_MAX为0。NULL宏甚至可以定义为
(void*)SIZE_MAX,这将由编译器从上下文中找出这与0具有相同的语义学。转换代码负责在指针中注意它是所选的值

伏默
2023-03-14

C

dcl.ref/5。

不应该有对引用的引用,没有引用数组,也没有指向引用的指针。引用的声明应包含初始化器(8.5.3),除非该声明包含显式外部说明符(7.1.1),是类定义中的类成员(9.2)声明,或者是参数或返回类型的声明(8.3.5);参见3.1。引用应被初始化为引用有效的对象或函数。[注意:特别是,空引用不能存在于定义良好的程序中,因为创建这种引用的唯一方法是将其绑定到通过空指针间接获得的“对象”,这会导致未定义的行为。如9.6中所述,引用不能直接绑定到位字段。-结束注释]

这条注释很有意思,因为它明确指出取消引用空指针是未定义的。

我敢肯定,它在更相关的上下文中在其他地方说了出来,但这已经足够好了。

周宸
2023-03-14

引用C时,取消引用空指针显然是本标准引用中未定义的行为(重点是我的):

(C11,6.5.3.2p4)“如果为指针分配了无效值,则一元 * 运算符的行为未定义。

102):“一元*运算符取消引用指针的无效值包括空指针、针对指向的对象类型不正确对齐的地址以及对象生命周期结束后的地址。”

C99中的报价完全相同,C89/C90中的报价相似。

 类似资料:
  • 空指针标识(nullptr)(其本质是一个内定的常量)是一个表示空指针的标识,它不是一个整数。(译注:这里应该与我们常用的NULL宏相区别,虽然它们都是用来表示空置针,但NULL只是一个定义为常整数0的宏,而nullptr是C++0x的一个关键字,一个内建的标识符。下面我们还将看到nullptr与NULL之间更多的区别。) char* p = nullptr; int* q = nullptr;

  • 问题内容: 我是GoLang的新手,来自Delphi C ++世界-诚然对这种语言感到非常兴奋,我认为它将成为“下一件大事”。 我正在尝试了解Go解析器和编译器如何处理指针和引用-似乎找不到任何放置一些明确规则的地方。 例如,在下面的代码示例中,返回类型和局部变量是指针类型,并且在其声明中需要使用指针符号,但是在使用时不必取消引用它们:。但是在同一代码中,输入参数被声明为指针,并且必须被取消引用才

  • 本文向大家介绍C语言取消引用指针,包括了C语言取消引用指针的使用技巧和注意事项,需要的朋友参考一下 示例 要取消引用a_pointer并更改a的值,我们使用以下操作 可以使用以下打印语句对此进行验证。 但是,将一个NULL指针取消引用或其他无效指针将是错误的。这个 通常是未定义的行为。p1可能不会被取消引用,因为它指向的地址0xbad可能不是有效地址。谁知道那里有什么?它可能是操作系统内存,或另一

  • 假设您知道您的软件只会在符号溢出行为定义良好的两台互补机器上运行。签名溢出在C和C中仍然是未定义的行为,编译器可以用“ret”替换整个程序,启动核战争,格式化驱动器,或者让恶魔从你的鼻子里飞出来。 假设您在内联 asm 中进行了签名溢出,您的程序是否仍会调用 UB? 如果是,那么单独编译和链接的汇编程序呢?

  • ISO C11标准在哪里规定,比较两个不指向同一个数组的指针(、、、)是未定义的行为?

  • 考虑以下C程序: null 访问易失性对象、修改对象、修改文件,或者调用执行那些操作中的任何操作的函数都是副作用,它们是执行环境状态的改变。表达式的计算通常包括值计算和副作用的启动。用于lvalue表达式的值计算包括确定指定对象的标识。 Sequenced before是单线程执行的计算之间的非对称、传递、成对关系,它导致这些计算之间的部分顺序。给定任意两个评价A和B,如果A排序在B之前,那么A的