其他分享
首页 > 其他分享> > 在C中,当表达式涉及该对象时,将表达式赋值给对象时是否存在已定义的操作顺序?

在C中,当表达式涉及该对象时,将表达式赋值给对象时是否存在已定义的操作顺序?

作者:互联网

考虑以下使用Qt容器类QMap的C代码:

#include <QMap>
#include <iostream>

QMap<int, int> myMap;

int count() {
    return myMap.size();
}

int main() {
    myMap[0] = count();
    std::cout << myMap[0] << std::endl;
    return 0;
}

根据myMap在执行count()之前或之后是否在其中创建了新条目,此代码的输出将分别为1或0.

此代码的输出是否依赖于QMap的实现?或者C规范是否对与QMap :: operator []执行count()的时间有何关系?或者结果是否未定义,这是最好避免的情况?

我问,因为我在一个正在进行的计划中有一个基本相同的情况.当我在Windows中编译程序并使用库存Qt 5.5.1 DLL运行它时,结果为0.但是,当我使用从源代码编译的另一组Qt 5.5.1 DLL运行它时,结果是1.这是一个非常令人困惑的错误,我花了一些时间来追踪,特别是因为根据我运行可执行文件的位置得到了不同的结果!

我希望我能理解同一个程序有两种不同的行为,以便我将来能够避免这样的错误.

解决方法:

你的问题在这里:

myMap[0] = count();

是整个赋值是一个表达式,对count()的调用是一个子表达式.表达式和子表达式之间没有序列点.

这不是关于评估顺序,而是关于副作用的排序.赋值有副作用,在这种情况下,它会向QMap添加一个新元素.只有在序列点,才能保证序列点之前的代码产生的所有副作用都已完成.

函数调用是一个序列点,但它在函数参数的评估和实际调用之间 – 与返回值无关.由于此处没有任何参数,因此在这种情况下不适用.

所以,是的,这是未定义的行为,你应该避免它.供参考,here’s a quite exhaustive answer on the topic of sequence points.

解决方案当然很简单:使用两个单独的语句.语句(;)的结尾始终是序列点.

标签:c,operator-precedence,qt
来源: https://codeday.me/bug/20190823/1699790.html