C++ 向返回意外结果的空指针地址添加整数

C++ 向返回意外结果的空指针地址添加整数,c++,c,pointers,null-pointer,C++,C,Pointers,Null Pointer,我试图通过在空指针的ASCII码中添加一些东西来打印地址0x14,我认为这是0地址。然而,当我将5添加到NULL时,我不明白为什么我得到的是0x14而不是0x20。我认为由于ptrNumA是一个指向整数的指针,它应该添加大约5个整数块,每个4字节,新地址应该是0x20 谢谢你的帮助。非常感谢。 技术上,NUMPTRA不指向数组,甚至不指向一个奇异对象,因此添加0以外的任何东西导致C++中的未定义行为,因为指针算法只针对数组和对象的边界中的指针定义。 这是最新的C++标准草案: [解释添加] 在指

我试图通过在空指针的ASCII码中添加一些东西来打印地址0x14,我认为这是0地址。然而,当我将5添加到NULL时,我不明白为什么我得到的是0x14而不是0x20。我认为由于ptrNumA是一个指向整数的指针,它应该添加大约5个整数块,每个4字节,新地址应该是0x20

谢谢你的帮助。非常感谢。

技术上,NUMPTRA不指向数组,甚至不指向一个奇异对象,因此添加0以外的任何东西导致C++中的未定义行为,因为指针算法只针对数组和对象的边界中的指针定义。 这是最新的C++标准草案:

[解释添加]

在指针类型的表达式p上加上或减去具有整数类型的表达式J时,结果的类型为p

如果P的计算结果为空指针值,而J的计算结果为0,则结果为空指针值。[不适用] 否则,如果P指向数组对象x的数组元素i,其中包含n个元素。。。[不适用]注意:在本规则中,指向对象的指针可视为1个元素的数组 否则,行为是未定义的。 除此之外,0x前缀还表示十六进制基数。5*4=20=0x14和0x20=32!=二十,

这就是说,空指针的值不一定是0,即使文本0始终是空指针文本,因此这种期望对于某些系统来说是不可移植的,而事实并非如此。这在需要地址0作为实际存储的嵌入式系统上是典型的


此外,当您将int*作为参数传递时,printf说明符%p要求参数的类型为void*。由于违反此约束,程序的行为未定义。

答案在注释中。
在您的例子中,sizeofint==4,因此numPtr+2点到地址8=2*4,numPtr+5点到地址20=5*4,这实际上是十六进制表示法中的0x14。

不允许对不指向有效对象的指针执行指针算术-根据6.5.6,详细信息和引号,这是未定义的行为。所以你可以从中得到任何结果

此外,在C语言中,空指针不能保证二进制表示为零。我建议学习


最后,%p给出十六进制的输出。指针算法的基本原理是typeptr+5等于将sizeof*typeptr*5相加,以字节表示。由于sizeofint很可能是0x4,因此得到的是0x4*0x5=0x14。

14十六进制是20位小数5*4=20=0x14请不要发布图像,除非必要。0x表示该值以16为基数。所以您期望的0x20是十进制32。0x并不意味着指针值。不要用C和C++来标记问题,除非它们涉及两种语言之间的交互,或者有一些特定的原因来询问两种语言之间的差异。C和C++对空指针和地址算术有不同的规范,同时询问两者都混淆了问题。如果您想查询这两种语言,可以在单独的问题中进行查询。@pqans简单地执行超出范围的指针算术是未定义的行为,无论您是否反引用结果。@pqans指向null的指针至少不能保证是指向对象的指针。即使是这样,添加一个大于1的值也会使一个元素的虚拟数组溢出,从而导致未定义的行为。@pqans示例程序的输出实际上并不表示未定义的行为。这无关紧要。缺少输出表明UB并不以任何方式证明缺少UB。不管您尝试了多少编译器。事实上,编译器最多做到了你所期望的是为什么我把这个违反看作是一个技术性的问题。@ PQANS:在C中,问题被标记为C和C++,如图所示初始化的NUMPTA没有指向地址0的int。当然,它的类型是“指向int的指针”,但它的值是空指针。首先,请注意空指针不一定指向“地址0”。由于C标准定义空指针常量的方式,当用作指针时,常量0由编译器转换为实现用于表示空指针的任何位组合。可以是0,0xFFFFFF,0xDEADBEEF,或任何其他值……其次,在C计算模型中,没有对象。C 2018 6.3.2.3 3规定空指针“保证与指向任何对象或函数的指针进行不相等的比较”。因此,如果numPtrA确实指向“地址0”或任何其他地址的int,则numPtrA==numPtrA必须根据6.5.9 6中的规则为真,但是我们会有一个空指针numPtrA,它与指向对象的指针numPtrA相比较,这违反了6.3.2.3。所以C标准中使用的模型是nu
ll指针不指向对象。本例中的指针指向地址0处的有效整数。@pqans No不一定指向。请阅读提供的有关空指针如何工作的链接。@pqans为了举例说明,您可能想思考一下为什么bananas\u t**bananas\u t*=void*0;干净地编译,但香蕉**香蕉*=void*1;给出编译器错误ISO C禁止在函数指针和void*Re“You's not allowed”之间初始化:我已经做了很多次,并且没有停止过一次。Re“%p给出了十六进制的输出”:在OP的实现中,并且通常不是根据标准的要求。请参见以下内容:。其中助记符ud2给出了一个无效的操作码,该操作码只会生成一个硬件指令陷阱。现在请解释为什么在void*0而不是void*1的情况下会发生这种情况。
#include <stdio.h>

int main() {
  int *numPtrA = NULL;         // pointer to an integer pointer to null.. ascii value of zero
 
  printf("%p\n", numPtrA + 2); // prints 0x8 which i expect
  printf("%p\n", numPtrA + 5); // prints 0x14 and i dont know why
}