如果我减少`std :: size_t(0)`保证等于`std :: size_t(-1)`?

Ben*_*Ben 3 c++ integer-overflow undefined-behavior unsigned-integer

以下证据表明:

inline
constexpr std::size_t prev(std::size_t i) {
    --i;
    return i;
}

int main() {
    static const std::size_t i = 0;
    static_assert(prev(i) == std::size_t(-1), "Decrementing should give     std::size_t(-1)");    
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

那个快乐地汇编着-std=c++14.

我遇到了这个,因为我有一个循环索引,std::vector并想要向后循环,所以我把它改为

for (std::size_t i = std::min(idx, v.size() - 1); i != std::size_t(-1); --i) { ... }
Run Code Online (Sandbox Code Playgroud)

现在,我意识到我可以使用std::vector::reverse_iterator,但我现在的真正问题是,我期待定义的行为是什么?

Yak*_*ont 6

size_t 是未指定的无符号整数.

C++中的所有无符号整数都被建模为模2 n的整数环的元素,用于特定于该无符号整数类型的某个数字n.

当您将有符号整数转换为无符号整数时,您将获得整数环中的值,模2 n为该无符号类型的常量n.对于-1,这是2 n -1.

当您将0作为无符号整数类型递减时,得到2 n -1.

这两个值是相同的.

参见C++标准中的[basic.fundamental] 3.9.1/4:

无符号整数应遵守算术模2 n的定律, 其中n是该特定整数大小的值表示中的位数.

(引用取自N3690,最近的标准草案,但它代表的事实不会很快改变;段落编号可能.)

查找有关如何从有符号整数进行转换的引用将涉及更多标准追逐; 但它最终成为你想要的.


Jus*_*tin 5

是的,这种行为是有保证的.

std::size_t是无符号整数类型.无符号整数的算术总是有明确定义的语义:

无符号整数运算总是以2 n为模执行 ,其中n是该特定整数中的位数.

特别考虑内置的预减量和后减量运算符:

[T]他的表达--x完全等同于x -= 1....
[T]表达式x--修改其操作数的值,就好像通过评估一样x -= 1

因此减量运算符确实执行算术运算.