我有一段记忆,我正在“守卫”,定义为
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; }
该标准规定:
所以我无法理解对于来自不同对象的任何指针的结果如何都是正确的(因为它会破坏区域内其中一个指针的不同规则)。
编辑:
用例是什么?
检测指针是否在区域内的能力非常重要,在某些时候编写代码
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:0000
和guardSize = 0x00020000
。 这意味着受保护的地址是0101:0000
到0101:FFFF
和0109:0000
到0109:FFFF
。 此外, guardArea + guardSize = 0111:0000
。
同时,假设有一些全局内存恰好在0108:0000
分配。 这是全局内存分配,因为选择器是偶数。
观察到全局内存分配不是受保护区域的一部分,但其指针值确实满足数字不等式0101:0000 <= 0108:0000 < 0111:0000
。
Bonus chatter :即使在具有平坦内存模型的CPU架构上,测试也会失败。 现代编译器利用未定义的行为并相应地进行优化。 如果他们看到指针之间的关系比较,则允许他们假设指针指向同一个数组(或者超过该数组的最后一个元素)。 具体来说,可以合法地与guardArea
进行比较的唯一指针是formsguardArea
, guardArea+1
, guardArea+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;
实际上允许ua
和ub
具有相同的值。 这种情况经常出现在分段系统(如MS-DOS)上,这可能会将代码和数据放在不同的段中。
以上就是c/c++开发分享以下代码可以用于指向不同事物的指针相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/549326.html