C是否有更多像NULL这样的宏?

C是否有更多像NULL这样的宏?,c,null,hashtable,C,Null,Hashtable,背景: 删除使用线性探测的哈希表中的单元格时,必须指明该单元格中曾经存在的值,但在搜索过程中可以跳过该值。解决此问题的最简单方法是添加另一个变量来存储此信息,但如果已知保证无效的内存地址并用于表示此状态,则可以避免使用此额外变量 问题: 我假设,由于0是一个保证无效的内存地址(通常情况下是无效的),因此必须存在不止一个NULL。所以我的问题是,C是否为任何其他保证无效的内存地址提供了一个标准宏?严格来说,NULL在运行时不需要数字为零。C在指针上下文中将0和NULL转换为实现定义的无效地址。该地

背景:

删除使用线性探测的哈希表中的单元格时,必须指明该单元格中曾经存在的值,但在搜索过程中可以跳过该值。解决此问题的最简单方法是添加另一个变量来存储此信息,但如果已知保证无效的内存地址并用于表示此状态,则可以避免使用此额外变量

问题:


我假设,由于0是一个保证无效的内存地址(通常情况下是无效的),因此必须存在不止一个NULL。所以我的问题是,C是否为任何其他保证无效的内存地址提供了一个标准宏?

严格来说,
NULL
在运行时不需要数字为零。C在指针上下文中将
0
NULL
转换为实现定义的无效地址。该地址通常在数字上为零,但C标准不能保证这一点。据我所知,C本身不提供任何保证与
NULL

不同的无效地址,从技术上讲,
NULL
不保证无效。仅保证不作为任何对象的地址(C11 6.3.2.3:3):

值为0的整型常量表达式或此类表达式 转换为void*类型称为空指针常量(66)。如果为空 指针常量转换为指针类型,结果为 指针,称为空指针,保证与 指向任何对象或函数的指针

(66)宏NULL在(和其他标头)中定义为NULL指针常量

您的使用也不要求特殊地址值无效:显然,您不会访问它,除非segfaulting是程序正常行为的一部分

因此,您可以使用任意多个对象的地址,只要这些对象的地址不打算成为单元格正常内容的一部分

例如,对于在指针到对象之间转换保留表示的体系结构,您可以使用:

char a, b, …;
#define NULL1 (&a)
#define NULL2 (&b)
…

您还可以创建自己的“无效”地址指针:

const void*const SOME_MARKER=(void*)&x


如果您确保
x
(或其地址)永远不能实际用于您想要使用
某些标记的地方,您应该是安全的,并且100%可移植的。

从技术上讲,地址0可能是一个有效的地址,例如在嵌入式系统上。然而,为了回答您的问题,C将
NULL
作为指向“NULL”(不必是
0
)的指针,仅此而已。为什么需要更多?NULL就足够了,并且是唯一的一个。在指针值中使用额外的位是一个常见的错误,顺便说一句,当体系结构发生变化时,结果会非常糟糕。@JoachimPileborg我知道NULL不是严格意义上的0,但我的问题是,因为编译器可以保证至少一个地址,为什么它不能保证更多?@MetaDark那么简单的答案是:编译器和运行库不需要这样做,那么为什么它们应该这样做呢?。规范规定必须有
NULL
和一些其他符号常量,但没有提及其他指针或地址。在实践中,
((char*)NULL)+1
((char*)NULL)-1
很可能无效。但这并不能保证,因为嵌入式系统可能有地址空间限制(例如,使用16位或32位指针而不是64位指针)。例如,
NULL
可能是最大的指针,而不是最小的指针,因此前一个表达式将溢出。同时,后一个表达式在大多数传统系统上是下溢的。我强烈建议不要依赖其中任何一个。这不是一个标准宏(我怀疑它是否存在),但它最终解决了问题,谢谢。