【发布时间】:2023-04-09 16:12:01
【问题描述】:
我是 C++ 的新手,还没有掌握该语言的所有复杂性和微妙之处。
在 C++11 中向任何类型的指针添加任意字节偏移量的最可移植、正确和安全的方法是什么?
SomeType* ptr;
int offset = 12345 /* bytes */;
ptr = ptr + offset; // <--
我在 Stack Overflow 和 Google 上找到了很多答案,但它们都提出了不同的建议。我遇到的一些变种:
-
ptr = (SomeType*)(((char*)ptr) + offset); -
投射到
unsigned int:ptr = (SomeType*)((unsigned int)ptr) + offset); -
ptr = (SomeType*)((size_t)ptr) + offset); -
“
size_t和ptrdiff_t的大小总是与指针的大小一致。因此,正是这些类型应该用作大型数组的索引,用于存储指针和指针运算。” - CodeProject 上的About size_t and ptrdiff_tptr = (SomeType*)((size_t)ptr + (ptrdiff_t)offset); -
或者像以前一样,但使用
intptr_tinstead ofsize_t,它是有符号的而不是无符号的:ptr = (SomeType*)((intptr_t)ptr + (ptrdiff_t)offset); -
只转换为
intptr_t,因为offset已经是一个有符号整数并且intptr_tis notsize_t:ptr = (SomeType*)((intptr_t)ptr) + offset);
在所有这些情况下,使用旧的 C 风格转换是否安全,或者为此使用 static_cast 或 reinterpret_cast 是否更安全或更便携?
我应该假设指针值本身是无符号的还是有符号的?
【问题讨论】:
-
没有。向指针添加任意字节偏移量是未定义的行为。你只能对指向同一个数组的指针进行算术运算(并且超过它的末尾)。
-
@jrok 将任意偏移量添加到指针是完美的定义。未定义的是取消引用不指向有效内存的指针。
-
@sfstewman 它不会导致我知道的实现错误,但是 IIRC 有一个条款禁止超过一个对象超出数组的末尾(即
int a[5]; a + 5;很好,int a[5]; a + 6不好)。编辑:找到来源:stackoverflow.com/a/988220/395760 -
@sfstewman:C++ 草案 n3092 5.7 5:“如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则评估不应产生溢出;否则,行为未定义。”
-
@sfstewman 你错了。该标准明确将其设为 UB(参见上面的评论)。在实践中,是的,它只是有效,至少在你粉碎自己的堆栈或类似的东西之前。
标签: c++ pointers c++11 pointer-arithmetic