在同一行上使用变量时的预增量操作符

Pre-Increment Operators when Using the Variable on the Same Line

本文关键字:变量 操作符 一行      更新时间:2023-10-16

我相信我想做的可能是有效的,因为它在两个实例中由逗号分隔(不是典型的赋值),但我不确定,搜索没有提出任何关于这两个特定情况的内容。

在这两种情况下,我都使用变量作为两个并行数组的索引。

int a[3] = {10, 20, 30};
int b[3] = {20, 40, 60};

情形#1:为数组

初始化结构体
struct testStruct {
     int t1;
     int t2;
};
int i = 0;
testStruct test = {a[++i], b[i]}

最后一行的预期结果:test = {20, 40}

情况#2:从数组中传递特定的值作为函数args

void testFunc(int t1, int t2) {
    // do stuff
}
int i = 0;
test(a[++i], b[i]);

终线预期结果:test(20, 40)

这是有效代码吗?如果是,它在所有编译器中都有效吗?

结果是我所期望的吗?如果是,是因为数组还是因为逗号?

谢谢!

从长远来看,我建议不要在代码中使用这种"技巧",这是维护的噩梦,很难解释。几乎总是有其他选择,例如以下代码:

testStruct test = {a[++i], b[i]}

可以改成:

++i ;
testStruct test = {a[i], b[i]}

话虽如此,在两个函数调用和初始化中都没有使用逗号操作符,逗号是语法元素,没有其他元素。

您的第一种情况定义得很好,尽管根据这是c++ 11还是c++ 11之前有一些警告。

在这两种情况下,每个逗号后面都有一个序列点,尽管在c++ 11之前没有指定求值的顺序。所以我们可以通过缺陷报告430看到c++ 11之前的情况,报告430说:

最近的GCC bug报告(http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11633)询问

的有效性
int count = 23;   int foo[] = { count++, count++, count++ };

是未定义的、未指定的还是其他的?

答案是(强调我的未来):

我相信标准很清楚,中的每个初始化表达式上面是一个完整表达式 (1.9 [intro.execution]/12-13;另请参阅Issue 392),因此在每一个之后都有一个序列点表达式(1.9 [intro.execution]/16)。我同意标准是这样做的似乎没有规定表达式求值的顺序,也许应该是这样。有人知道有哪个编译器不会这样做吗从左到右求值表达式?

在c++ 11中,它被写入了c++ 11标准草案的8.4.5段,其中说:

在大括号初始化列表的初始化器列表中初始化子句,包括任何由包展开产生的子句(14.5.3), 按它们出现的顺序求值。也就是说,每一个值的计算和副作用与给定的在每个值计算和之前对初始化子句进行排序副作用与它后面的任何初始化子句相关联初始化器列表的逗号分隔列表。

我将继续使用c++ 11,因为它不会改变其余内容的答案,尽管排序的措辞确实有所不同,但结论是相同的。

第二种情况调用了未定义的行为,因为函数参数的求值顺序是未指定的,它们的求值顺序是不确定的。我们可以从1.915中看到这种未定义的行为,其中说:

除特别说明外,单个操作符的操作数求值并且单个表达式的子表达式都是无序的。(注意:在运算过程中被求值多次的表达式中执行未排序和未确定排序的程序它的子表达式的求值不需要一致地执行在不同的评估中。-end note]的值的值计算之前对操作符的操作数进行排序运算符的结果。如果标量对象的副作用是相对于同一标量上的另一个副作用的非排序对象或使用相同标量的值进行值计算.

,并提供如下示例:

f(i = -1, i = -1); // the behavior is undefined

第一个代码片段

testStruct test = {a[++i], b[i]};

是有效的(如果要添加分号),因为根据c++标准

4在大括号初始化列表的初始化器列表中初始化子句,包括任何由包展开产生的子句(14.5.3),按它们出现的顺序求值。也就是说,每一个值的计算和副作用与给定的在每个值计算和之前对初始化子句进行排序与后面的任何初始化子句相关的副作用初始化器列表的逗号分隔列表。

考虑到编译器GCC 4.8.1有(或至少曾经有过)我所描述的一个错误

这里的

虽然描述是用俄语写的,但你可以使用例如google "translate"服务进行翻译

但是第二个代码片段

test(a[++i], b[i]);

具有未定义的行为,因为函数参数的求值顺序未指定。

你可以写

test( { a[++i], b[i] } );

在这种情况下,表达式将是格式良好的