据我所知,C / C ++中不允许使用++i++
之类的东西,因为它们破坏了一个规则,即变量不能在一个语句中多次写入。结果是未定义的行为。
有人可以确认这是否也适用于我的陈述:++i %= j
?
我想要一个for循环,我从i
的任意点开始围绕循环缓冲区(大小j
)递增p
,直到我回到p
点
for(int i = p+1 ; i != p; ++i %= j )
{
if (buffer[i].ready())
{
buffer[i].do_something();
p = i;
break;
}
}
我可以在更多代码行中完成,但不愿意。
答案 0 :(得分:4)
在您的代码中,您说++i % j
,这意味着'递增i(并将新值存储在i中),然后计算i和j的模数。但是这个值并没有存储在任何地方。
要获得环绕循环,您可以使用i = (i+1)%j
答案 1 :(得分:2)
++i %= j
相当于i = ++i % j
。
这是i = ++i
的打扮版本,而每个人都知道这是UB。
答案 2 :(得分:2)
是的,您的代码定义明确(无论如何在C ++ 17中)。引用标准:
赋值运算符(=)和复合赋值运算符all 从右到左分组。所有都需要左侧可修改的左值 操作数并返回一个引用左操作数的左值。结果 在所有情况下,如果左操作数是位字段,则是位字段。 总之 在这种情况下,赋值在值的计算之后排序 左右操作数,以及之前的值计算 赋值表达式。 右操作数在左前排序 操作数。关于不确定顺序的函数调用, 复合赋值的操作是单一的评估。
前缀++的操作数通过加1来修改。操作数应为 一个可修改的左值。操作数的类型应为算术运算 除了cv bool之外的类型,或者指向完全定义的对象的指针 类型。 结果是更新的操作数;它是一个左值,,它是一个 如果操作数是位字段,则为位字段。表达式++ x是 相当于x + = 1。
粗体文本表示您的代码几乎具有以下语义:
auto& __j = j; // refer to j
auto& __i = ++i; // refer to i after the increment
__i %= __j;
如果标准保证,表达式看起来很可疑,您可以随时使用逗号运算符对其进行排序。
for(... ; ... ; (++i, i %= j))
答案 3 :(得分:2)
代码++i %= j
与以下代码相同:
operator %= (++i, j);
在标准(§1.9/ 15)中,它表示
运算符操作数的值计算在运算符结果的值计算之前排序。
“价值计算”包括:
所以,在这里,编译器必须首先计算++i
和j
(按任意顺序),包括++
的副作用,并仅调用operator %=
这些计算结束后。所以,至少从C ++ 11开始,这是一个明确定义的行为。
有关详细信息,请参阅this answer。
答案 4 :(得分:0)
其他人已经回答过你的代码是有效的C ++ 11及更高版本,但对于早期版本的C ++来说是未定义的行为,甚至不能用C编译(当然忽略类成员fcn调用)。所有这些都说你应该使用更明确的形式来实现你想要的目标。
我还想指出,p == j - 1
代码可能会在您的代码中出现一个微妙的错误,因为您在初始化i
时添加了一个但不是mod,这样您就可以访问那种情况下的数组。
您也永远不会处理索引p
处的元素。那真的你想要什么?如果您反复执行此代码并且其他缓冲区都不是ready()
,那么您将继续跳过检查是否buffer[p].ready()
。
更正确,更通用的代码(仍未检查索引p
处的元素):
int i;
for (i = (p + 1) % j; i != p && !buffer[i].ready(); ++i, i %= j);
if (i != p)
{
buffer[i].do_something();
p = i;
}
通过处理索引p
处的元素开始的版本,但在最多遍历一次数组后停止:
int i = p;
while (!buffer[i].ready() && (++i, i %= j, i != p));
if (buffer[i].ready())
{
buffer[i].do_something();
p = i;
}
上述版本有一个微妙的意义。如果!buffer[p].ready()
在我们第一次进入循环时,我们遍历整个数组,其他元素都没有ready()
,那么我们将使用i == p
退出循环。然后,我们将再次询问buffer[p]
是否为ready()
。因此,可以两次询问buffer[p].ready()
,这可能重要也可能不重要(例如 - 如果它有副作用)。抬头!
这是一个避免该问题的版本,但最后检查buffer[p].ready()
:
int i = p;
while ((++i, i %= j, i != p) && !buffer[i].ready());
if (i != p || buffer[p].ready())
{
buffer[i].do_something();
p = i;
}