C:两个空指针的区别是什么?

C:两个空指针的区别是什么?,c,pointers,alignment,void,C,Pointers,Alignment,Void,如果我减去两个空指针,我会得到指针位置之间的相对距离(至少在我的测试系统上是这样)。我应该使用什么类型来存储结果,以便与64位系统兼容?尺寸是正确的类型还是可能较长 背景:我们需要检查给定的void指针是否可以安全地用作双指针。我们曾经将指针强制转换为int,并检查低三位是否为零,但是我们当前的编码标准不再允许将指针强制转换为整数类型。我正在考虑计算void指针和NULL指针之间的差值,并检查该差值是否可以除以8。假设空指针始终是8字节对齐的?来自C11,6.5.6加法运算符/9(我的斜体):

如果我减去两个空指针,我会得到指针位置之间的相对距离(至少在我的测试系统上是这样)。我应该使用什么类型来存储结果,以便与64位系统兼容?尺寸是正确的类型还是可能较长


背景:我们需要检查给定的void指针是否可以安全地用作双指针。我们曾经将指针强制转换为int,并检查低三位是否为零,但是我们当前的编码标准不再允许将指针强制转换为整数类型。我正在考虑计算void指针和NULL指针之间的差值,并检查该差值是否可以除以8。假设空指针始终是8字节对齐的?

来自
C11,6.5.6加法运算符/9(我的斜体):

当减去两个指针时,两个指针都应指向同一数组对象的元素,或指向数组对象最后一个元素之后的元素;结果是两个数组元素的下标不同。结果的大小由实现定义,其类型(有符号整数类型)为
标题中定义的
ptrdiff\u t

在这一节中,从指针中减去NULL在技术上也是未定义的行为,因为
NULL
不能被视为指向同一数组的元素的指针,也不能被视为指向该数组之外的元素的指针。指针减法实际上仅限于获取同一数组中两个元素之间的索引差

因此,您可能需要重新考虑您正在进行的检查,特别是考虑到事实上double实际上不需要八个字节长,而且即使需要八个字节长,标准中也没有要求它在八个字节的边界上对齐

我更倾向于在函数的文档中声明,传递的值必须是有效的
double
指针,如果函数的用户违反该约定,则所有赌注都将被取消

如果我减去两个空指针,我会得到指针位置之间的相对距离(至少在我的测试系统上是这样)

减去两个指针有一条严格的规则。C11-§6.5.6:

当减去两个指针时,两个指针都应指向同一数组对象的元素,或指向数组对象最后一个元素之后的元素;结果是两个数组元素的下标不同。[……]


两个空指针的区别是什么

它应该是
ptrdiff\u t

[…]结果的大小由实现定义,其类型(有符号整数类型)为
标题中定义的
ptrdiff\u t
。[……]


C标准中没有定义空指针的减法。只有当指针都指向同一个数组时,才能定义指针减法,而空指针不能指向任何数组,因为不能有包含空元素的数组


很可能您使用的是gcc或其他兼容的东西,它允许将void指针上的算术作为扩展,并将其视为char指针。但严格的C编译器不应允许在无效指针上进行指针运算。

问题概述:

  • 您将null指针常量宏null与null指针混淆。这是两个不同的术语。NULL宏始终等于0,但NULL指针可以有任何值

  • 这就是说,使用空指针或空宏执行指针算术没有任何意义。这样做会调用未定义的行为,因为指针必须指向同一数组。请参见paxdiablo的答案

  • 此外,正如Art在回答中指出的,您不能对空指针执行任何形式的算术。+和-运算符规定为(6.5.6):

    对于加法,两个操作数都应具有算术类型,或者一个操作数具有算术类型 操作数应为指向完整对象类型的指针,另一个为 应具有整数类型

    无效指针是指向不完整类型的指针,因此,如果其中一个或两个操作数都是无效指针,则代码是无效的C

    注意,GCC有一个非标准扩展,它允许使用void指针算法,在这种情况下,它将void指针视为指向字节的指针。如果您打算编写安全且可移植的程序,请不要使用此非标准功能。如果您希望gcc作为标准C编译器(一致性实现),请使用
    gcc-std=c11-pedantic errors进行编译


在我们的系统(基于PowerPC)上,双精度必须在8字节边界上对齐。我知道签入本身是不可移植的,但它仍然是必要的。@slingeraap好奇:当指针未对齐时,你的代码会做什么?我们确实在使用gcc。@slingeraap然后将其配置为一个合适的C编译器:
-std=c11-学究错误
。当您尝试执行非标准垃圾操作时,将出现编译器错误。“我们当前的编码标准不再允许将指针强制转换为整数类型。”——>太糟糕了,您无法强制转换为
uintptru\t