【问题标题】:C++ size_t or ptrdiff_tC++ size_t 或 ptrdiff_t
【发布时间】:2010-12-07 13:51:16
【问题描述】:

如果你有以下代码,其中 p 是一个指针:

p = p + strlen(p) + size_t(1);

由于strlen()size_t 都是size_t,我应该将代码转换为ptrdiff_t 吗?

p = p + (ptrdiff_t)(strlen(p) + size_t(1));

如果是,为什么?

谢谢, 格雷格

【问题讨论】:

  • 您尝试做的是无效的 C++,因为p + (ptrdiff_t)(strlen(p) + size_t(1)) 地址不在p 指向的字符数组中。
  • 不一定。 p 数组不需要在 null 处结束。
  • @JB Jansen:一般情况下你无法知道——这取决于p 的内存是如何分配的。 C 中没有什么可以阻止字符串比托管它的内存块更短(!)。
  • @JB、Alex、FrankH:无论如何,在过去的最后一个内存位置构造一个指向内存位置的指针是定义明确且正常的。例如,std::vector::end() 就是这样做的。您不能取消引用该指针,但它对所有其他指针操作都是明确有效的。标准中的相关引用:除非两个指针都指向同一个数组对象的元素,或超过数组对象的最后一个元素,否则行为未定义。跨度>
  • 还应该注意,这里真的不需要 size_t 转换。编译器可能会抱怨“有符号/无符号不匹配”,在这种情况下,正确的解决方法是编写 1u1ul 而不是强制转换。

标签: c++


【解决方案1】:

std::ptrdiff_t 已签名。 std::size_t 未签名。如果p 的长度可以为负,那么将strlen(p) 转换为ptrdiff_t 是有意义的,这是不可能的。

但是,如果 p 足够大(例如,在大多数 32 位平台上大于 2,147,483,647 字节),则该强制转换可能会溢出结果有符号值。所以它可能会在你的指针算法中引入一个错误。

最好在此处使用size_t

【讨论】:

  • ptrdiff_t 似乎坏了,无论如何,因为 2G 不足以表示指向 3G 数组的第一个和最后一个元素的指针的差异。如果您以任何方式使用 ptrdiff_t 数据类型,您的程序就有错误。 en.cppreference.com/w/cpp/types/ptrdiff_t
  • @VaddadiKartick 在 64 位系统上 PTRDIFF_MAX 等于 9223372036854775807 看起来足够了。
【解决方案2】:

无需转换为ptrdiff_t。指针算法对所有整数类型都有很好的定义,包括size_t,如果size_t 不足以容纳该值,那么转换为ptrdiff_t 无论如何都太晚了。

这是标准中的相关语言(C++0x FCD,[expr.add] 部分):

当一个表达式具有整数 类型被添加到或减去 指针,结果的类型为 指针操作数。如果指针 操作数指向一个元素 数组对象,并且数组很大 够了,结果指向一个 元素与原始元素的偏移 元素这样的差异 结果的下标和 原始数组元素等于 积分表达式。换句话说, 如果表达式 P 指向 i - 数组对象的第一个元素,表达式 (P)+N(等价于, N+(P)) 和 (P)-N(其中 N 具有 值 n ) 分别指向 i + n -th 和 i - n -th 元素 数组对象,前提是它们存在。 此外,如果表达式 P 指向 到数组的最后一个元素 对象,表达式 (P)+1 分 过去数组的最后一个元素 对象,如果表达式 Q 指向 一个数组的最后一个元素 对象,表达式 (Q)-1 指向 数组对象的最后一个元素。 如果指针操作数和 结果指向相同的元素 数组对象,或最后一个 数组对象的元素, 评估不应产生 溢出;否则,行为是 未定义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-02
    • 2019-01-26
    • 1970-01-01
    • 2015-07-28
    • 1970-01-01
    • 2014-08-15
    • 2018-05-08
    相关资源
    最近更新 更多