何时需关注数组偏移量溢出?同尺寸索引与偏移类型安全性探讨
同尺寸无符号索引与有符号偏移量的溢出安全性分析
当数组偏移量类型与索引类型的sizeof相同时,是否需要关注偏移量值的溢出问题?
从直观角度看,有符号偏移量的取值范围仅为无符号索引的一半,当偏移量超过索引寻址范围的一半时会发生溢出,但结合C++标准的相关条款,我们可以得出更准确的结论:
C标准3.9.1.4条款:无符号整数需遵循模2ⁿ算术法则(n为该整数的值表示位数)
C标准5.3.1.8条款:无符号量的负值通过将其值从2ⁿ中减去计算(n为提升后操作数的位数)
基于上述标准,使用同尺寸的无符号类型作为索引、有符号类型作为偏移量在以下操作场景中是安全的:
- 索引与偏移量相加
- 根据计算得到的新索引获取元素
- 比较两个计算得到的索引
注:暂不涉及两个偏移量的比较,这属于另一种需要单独分析的场景。
以下代码可验证这一结论:
#include <iostream> #include <limits> using index_t = unsigned int; using offset_t = signed int; int main() { index_t index = 100; const offset_t extra_offset = 1000; offset_t offset_large = std::numeric_limits<offset_t>::max() + extra_offset; // 形式上偏移量发生溢出 long long int output_convestion; index_t position_large = index + offset_large; output_convestion = position_large; long long int position = index; position += std::numeric_limits<offset_t>::max(); position += extra_offset; std::cout << "Position large = " << output_convestion << " should be = " << position << (output_convestion == position ? " (equal) " : "(different)") << '\n'; }
不过,我是否遗漏了某些可能导致问题的情况?
另外,选择同尺寸偏移量而非更大尺寸类型的原因如下:
- 希望在大型偏移量数组中节省内存空间
- 现有代码生态中,针对
std::size_t类型的索引,多数实现会使用与其尺寸相同的有符号类型std::ptrdiff_t作为偏移量,本文旨在正式解答这一常见实践的安全性问题。
内容的提问来源于stack exchange,提问作者Damir Tenishev
相关产品推荐
相关产品推荐

