以下代码可以用于指向不同事物的指针

我有一段记忆,我正在“守卫”,定义为

typedef unsigned char byte; byte * guardArea; size_t guardSize; byte * guardArea = getGuardArea(); size_t guardSize = getGuardSize(); 

为此目的可接受的实现是:

 size_t glGuardSize = 1024; /* protect an area of 1kb */ byte * getGuardArea() { return malloc( glGuardSize ); } size_t getGuardSize() { return glGuardSize; } 

以下代码段可以为任何指针(来自不同的malloc,来自堆栈等)返回true吗?

 if ( ptr >= guardArea && ptr < (guardArea + guardSize)) { return true; } 

该标准规定:

  • 区域内的值将返回true。 (当ptr是成员时,所有行为都正确。)

  • 指针将是不同的(a == b只有它们是相同的)。

  • 可以通过递增基数来访问字节数组中的所有地址。
  • 任何指针都可以转换为char *,而不会损坏。

所以我无法理解对于来自不同对象的任何指针的结果如何都是正确的(因为它会破坏区域内其中一个指针的不同规则)。

编辑:

用例是什么?

检测指针是否在区域内的能力非常重要,在某些时候编写代码

 if ( isInMyAreaOfInterest( unknownPointer ) ) { doMySpecialThing( unknownPointer ); } else { doSomethingElse( unknownPointer ); } 

我认为语言需要通过使这样的结构简单明了来支持开发人员,并且我们对标准的解释是开发人员需要转换为int。 由于不同对象的指针比较的“未定义行为”。

我希望能清楚地知道为什么我不能做我想做的事情(我的片段),因为我发现的所有post都说标准声称未定义的行为,没有任何解释,或者为什么标准更好的例子比我希望它如何工作。

目前,我们有一条规则,我们既不理解规则存在的原因,也不了解规则是否有助于我们

post示例:

SO:检查指针是否在malloced区域

SO:C比较指针

尽管指针没有指向区域,但分配仍然可以生成满足条件的指针。 例如,这将发生在受保护模式的80286上,Windows 3.x在标准模式和OS / 2 1.x中使用该模式。

在这个系统中,指针是32位值,分成两个16位部分,传统上写为XXXX:YYYY 。 第一个16位部分( XXXX )是“选择器”,它选择64KB的存储区。 第二个16位部分( YYYY )是“偏移”,它在该64KB存储区中选择一个字节。 (这比这更复杂,但是为了讨论的目的,我们就把它留在那里。)

大于64KB的内存块被分解为64KB块。 要从一个块移动到下一个块,请将8添加到选择器。 例如, 0101:FFFF之后的字节是0109:0000

但是为什么要添加8来移动到下一个选择器呢? 为什么不只是增加选择器? 因为选择器的底部三位用于其他事情。

特别是,选择器的底部位用于选择选择器表。 (让我们忽略位1和2,因为它们与讨论无关。为方便起见,假设它们始终为零。)

有两个选择器表,全局选择器表(用于跨所有进程共享的内存)和本地选择器表(用于单个进程的私有内存)。 因此,可用于处理专用存储器的选择器是0019等。同时,可用于全局存储器的选择器是0008等。(选择器0000被保留。)

好的,现在我们可以设置我们的反例。 假设guardArea = 0101:0000guardSize = 0x00020000 。 这意味着受保护的地址是0101:00000101:FFFF0109:00000109:FFFF 。 此外, guardArea + guardSize = 0111:0000

同时,假设有一些全局内存恰好在0108:0000分配。 这是全局内存分配,因为选择器是偶数。

观察到全局内存分配不是受保护区域的一部分,但其指针值确实满足数字不等式0101:0000 <= 0108:0000 < 0111:0000

Bonus chatter :即使在具有平坦内存模型的CPU架构上,测试也会失败。 现代编译器利用未定义的行为并相应地进行优化。 如果他们看到指针之间的关系比较,则允许他们假设指针指向同一个数组(或者超过该数组的最后一个元素)。 具体来说,可以合法地与guardArea进行比较的唯一指针是formsguardAreaguardArea+1guardArea+2 ,..., guardArea + guardSize 。 对于所有这些指针,条件ptr >= guardArea为true,因此可以优化,将测试减少到

 if (ptr < (guardArea + guardSize)) 

对于数字上小于guardArea指针,现在将满足。

故事的道德 :这段代码不安全,甚至在平面架构上也是如此。

但并没有丢失 :指向整数的转换是实现定义的,这意味着您的实现必须记录它的工作原理。 如果您的实现将指针到整数的转换定义为生成指针的数值,并且您知道自己处于扁平体系结构中,那么您可以做的是比较整数而不是指针 。 整数比较的约束方式与指针比较的方式不同。

 if ((uintptr_t)ptr >= (uintptr_t)guardArea && (uintptr_t)ptr < (uintptr_t)guardArea + (uintptr_t)guardSize) 

是。

 void foo(void) {} void(*a) = foo; void *b = malloc(69); uintptr_t ua = a, ub = b; 

实际上允许uaub具有相同的值。 这种情况经常出现在分段系统(如MS-DOS)上,这可能会将代码和数据放在不同的段中。