在同一行上使用变量时的预增量操作符
Pre-Increment Operators when Using the Variable on the Same Line
我相信我想做的可能是有效的,因为它在两个实例中由逗号分隔(不是典型的赋值),但我不确定,搜索没有提出任何关于这两个特定情况的内容。
在这两种情况下,我都使用变量作为两个并行数组的索引。
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.9
段15中看到这种未定义的行为,其中说:
除特别说明外,单个操作符的操作数求值并且单个表达式的子表达式都是无序的。(注意:在运算过程中被求值多次的表达式中执行未排序和未确定排序的程序它的子表达式的求值不需要一致地执行在不同的评估中。-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] } );
在这种情况下,表达式将是格式良好的
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 将数组的地址分配给变量并删除
- 为"adjacent"变量赋值时出现问题
- enum是C++中的宏变量还是整数变量
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 获取/释放通过[]操作符访问的原子变量的语义
- 调用转换操作符不能用于静态const变量
- 用花括号代替赋值操作符声明和实例化作用域变量
- 操作符重载等同于c++中的PHP, echo/print类变量作为默认输出
- 在同一行上使用变量时的预增量操作符
- 为具有引用成员变量的类创建赋值操作符
- 如何声明操作符/重载函数来操作const变量和非const变量
- 操作符+()选择右值引用变量而不是const左值变量
- 当操作符地址可以设置为普通变量时,为什么要求从函数返回地址?
- 从模板化的类赋值操作符访问私有成员变量
- 给定了一个变量,编译器是否总能安全地创建赋值操作符?
- 执行free()操作符从动态变量中删除地址
- 如果存在三个变量,则使用范围解析操作符
- mfccstring中的变量和转换操作符