【问题标题】:Stuffing a -1 in a pointer as a special value在指针中填充 -1 作为特殊值
【发布时间】:2014-07-08 16:47:16
【问题描述】:

在 C 语言中,是否可以使用 this one 之类的方法将 -1 值(例如 0xFFFFFFFF)填充到指针中,并期望在运行时永远不会分配这样的内存地址?

这个想法是将指针值用作内存地址,除非它具有这个“特殊”-1 值。指针即使是 NULL 也应该被认为是内存地址(在这种情况下,它指向的对象还没有被构建)。

我了解这可能与平台有关,但相关程序预计可在 Linux、Windows 和 MacOSX 中运行。

手头的问题比这里描述的要大得多,所以 cmets 或回答这个方法没有用的问题。我知道这有点 hacky,但替代方案是一个主要的重构:/

提前致谢。

【问题讨论】:

  • 其实我不确定我是否得到你的问题。基本上 NULL 是等于地址的地址。那么为什么不只使用NULL呢?更不用说它在某些平台上的值可能为 0xFFFFFFFF。
  • 你为什么不分配一个静态哨兵变量,而不是写任何东西给它,而是保留一个地址?您可以确定没有任何有效地址与此哨兵的地址一致。
  • +1 帕斯卡·库克。也可以将任何函数的地址(例如,main)作为标记。
  • @faken 据我所知,&sentinel 是一个“常量表达式”(在 C99 6.6 的意义上),可以在初始化程序中使用。为什么需要任何代码?
  • 这就是 sqlite 的作用:sqlite.org/c3ref/c_static.html

标签: c pointers reserved


【解决方案1】:

它是 GRAS(通常被认为是安全的)。没有主要操作系统会分配与您选择的哨兵冲突的内存。然而,有一些病态的情况下,做出这种假设是无效的。例如,病态的 C++ 编译器可能会选择从 0xFFFFFFFF 开始堆栈,而不会违反规范中的任何约束。

在正常操作系统的范围内,几乎不可能将 0xFFFFFFFF(或其 64 位等效项)作为有效的内存地址。它不能是数组的有效内存地址(C++ 规则禁止它)。从技术上讲,它可能是在空间末尾分配的对象的 char 的有效索引,但有两件事可以防止这种情况发生。

  1. 大多数操作系统都有一些填充
  2. 大多数操作系统使用高内存值作为内核内存。

如果你有机会使用一个全局值作为哨兵,那么它肯定是安全的。

char sentinel;

char* p = "Hello";
char* p2 = 0; // null pointer
char* p3 = &sentinel;

if (p3 == &sentinel)
    cout << "p3 was a sentinel" << endl;

【讨论】:

  • 感谢@CortAmmon,您的回答似乎正确,但帕斯卡在评论中首先回答了它,所以我会将他的回答标记为正确的。不过一定要投赞成票。再次感谢。
  • @CortAmmon 什么低整数地址(1-4095)?我知道 Linux 将这些映射为不可访问。我对其他操作系统很好奇。毫无疑问,与静态地址相比,常量地址具有一些优势。
【解决方案2】:

定义一个没有其他有效地址会与之重合的标记值的一种方法是静态变量:

static t sentinel;
t *p = &sentinel;

如果您要假设一个平坦的地址空间并且所有指针具有相同的宽度,您可以通过声明sentinel 类型为char 而不是t 来最小化开销。


回答你关于(t*)-1的问题:

  • -1 的类型为 int。我会推荐(t*)(uintptr_t)-1,即使对于 64 位平面地址空间,它也更有可能是最后一个地址。

  • 它不是很干净,但它应该适用于所有常见的体系结构,因为只要编译器打算使用无符号比较汇编指令(通常这样做)比较指针,对于任何对象a编译器可能希望放置在地址空间的末尾,&amp;a + 1 必须比较大于&amp;a。实际上,这可以防止最后一个地址被用来存储任何东西。

【讨论】:

  • 再次感谢帕斯卡。我使用 GLib 的类型转换宏(我认为按照你的建议去做),所以将 -1 转换为整数是我的工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-26
  • 2021-08-11
  • 1970-01-01
  • 1970-01-01
  • 2017-11-07
  • 1970-01-01
相关资源
最近更新 更多