可以使用std :: uintptr_t来避免越界指针算法的未定义行为吗?

Jam*_*ree 7 c++ pointers pointer-arithmetic

现在我们知道,越界 - 指针算术具有未定义的行为,如本SO问题所述.

我的问题是:我们可以通过转换为std :: uintptr_t进行算术运算然后转换回指针来解决这种限制吗?是保证工作吗?

例如:

char a[5];
auto u = reinterpret_cast<std::uintptr_t>(a) - 1;
auto p = reinterpret_cast<char*>(u + 1); // OK?
Run Code Online (Sandbox Code Playgroud)

真实世界的用法是优化偏移内存访问 - 而不是p[n + offset]我想做的offset_p[n].

编辑使问题更明确:

给定一个pchar数组的基指针,如果p + n是一个有效的指针,将reinterpret_cast<char*>(reinterpret_cast<std::uintptr_t>(p) + n)保证产生相同的有效指针?

Kei*_*son 13

不,在执行指针运算时uintptr_t不能有意义地用于避免未定义的行为.

首先,至少在C中,不能保证uintptr_t甚至存在.要求是任何类型的值void*都可以转换为uintptr_t和返回,从而产生原始值而不会丢失信息.原则上,可能没有任何无符号整数类型足以容纳所有指针值.(我认为这同样适用于C++,因为C++继承了大部分C标准库,并通过引用C标准来定义它.)

即使uintptr_t存在,也不能保证对uintptr_t值的给定算术运算与指针值上的相应操作具有相同的作用.

例如,我曾在系统(Cray矢量系统,T90和SV1)上工作,字节指针在软件中实现.本地地址是64位地址,指的是64位字; 字节寻址没有硬件支持.A char*void*指针由一个字指针组成,其中3位偏移存储在否则未使用的高位中.整数和指针之间的转换只是复制位.因此,递增a char*将使其前进到指向内存中的下一个8位字节; 递增a uintptr_t通过转换a char*将使其前进以指向下一个64位字.

这只是一个例子.更一般地,指针和整数之间的转换是实现定义的,并且语言标准不保证这些转换的语义(在某些情况下,转换回指针除外).

所以是的,您可以将指针值转换为uintptr_t(如果该类型存在)并对其执行算术而不会有未定义的行为风险 - 但结果可能有意义,也可能没有意义.

事实上,在大多数系统中,指针和整数之间的映射更简单,你可能可以逃脱这种类型的游戏.但是你最好直接使用指针算法,并且要非常小心避免任何无效操作.


Jes*_*der 5

是的,这是合法的,但是您必须 reinterpret_castuintptr_t值完全相同char*

(因此,您打算执行的操作是非法的;也就是说,将不同的值转换回指针。)

5.2.10重新解释演员

4。指针可以显式转换为足够大的整数类型以容纳它。映射功能是实现定义的。

5。整数类型或枚举类型的值可以显式转换为指针。转换为足够大小的整数(如果实现中存在此类指针)并返回相同指针类型的指针将具有其原始值;

(请注意,一般而言,编译器没有办法知道您减去了一个后再加回去。)

  • 谢谢,这显然回答了我的疑问。因此,标题问题的答案应该为否。 (2认同)