以参数评估顺序警告UB [英] Warn about UB in argument evaluation order

查看:40
本文介绍了以参数评估顺序警告UB的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近在这样的代码中遇到了一个错误

I recently faced a bug in a code like this

class C
{
public:
    // foo return value depends on C's state
    // AND each call to foo changes the state.
    int foo(int arg) /*foo is not const-qualified.*/ {}

private:
    // Some mutable state
};

C c;

bar(c.foo(42), c.foo(43))

最后一次调用在不同平台上的行为有所不同(由于参数评估的顺序不确定,因此完全合法),并且我修复了该错误.

The last call behaved differently on different platforms (which is perfectly legal due to undefined order of argument evaluation), and I fixed the bug.

但是其余的代码库很大,我想发现所有其他这种类型的UB.

But the rest codebase is large and I would like to spot all other UB of this type.

在这种情况下,在GCC,Clang或MSVS中是否有特殊的编译器警告?

Is there a special compiler warning in GCC, Clang or MSVS for such cases?

防止这种错误的意识形态和轻量级方法是什么?

And what is the ideomatic and lightweight way to prevent such bugs?

推荐答案

参数顺序评估未指定,而不是未定义.

几乎所有C ++运算符的操作数求值顺序(包括函数调用表达式中的函数自变量的求值顺序和任何表达式中子表达式的求值顺序)未指定.编译器可以按任何顺序求值操作数,并且在再次求同一个表达式时可以选择其他顺序.

Order of evaluation of the operands of almost all C++ operators (including the order of evaluation of function arguments in a function-call expression and the order of evaluation of the subexpressions within any expression) is unspecified. The compiler can evaluate operands in any order, and may choose another order when the same expression is evaluated again.

由于未指定行为而不是未定义行为,因此不需要编译器为其发出诊断.

Since it is unspecified rather than undefined behavior, compilers are not required to issue diagnostics for it.

GCC和Clang没有任何常规的编译器选项可以发出针对未指定行为的诊断.

GCC and Clang do not have any general compiler option to issue diagnostics for unspecified behavior.

在GCC中,有一个 fstrong-eval-order 可以做到这一点:

In GCC there is the option fstrong-eval-order which does this:

按照C ++ 17的要求,按从左到右的顺序评估成员访问,数组下标和移位表达式,并按从右到左的顺序评估赋值.默认启用 -std = c ++ 17 . -fstrong-eval-order = some 仅启用成员访问和移位表达式的排序,并且是不带 -std = c ++ 17 的默认设置.

Evaluate member access, array subscripting, and shift expressions in left-to-right order, and evaluate assignment in right-to-left order, as adopted for C++17. Enabled by default with -std=c++17. -fstrong-eval-order=some enables just the ordering of member access and shift expressions, and is the default without -std=c++17.

还有 -Wreorder 选项(仅适用于C ++和Objective-C ++),可以执行以下操作:

There is also the option -Wreorder (C++ and Objective-C++ only) which does this:

当代码中给定的成员初始化程序的顺序与执行它们的顺序不匹配时发出警告

Warn when the order of member initializers given in the code does not match the order in which they must be executed

但是我认为这些选项对您的具体情况没有帮助.

But I do not think these options will be helpful in your particular case.

在下面的语句中,如果要在第二个参数之前对第一个参数求值:

In the below statement, if you want the first argument to be evaluated before the second:

bar(c.foo(42), c.foo(43))

简单的方法是先将 c.foo(42) c.foo(43)的结果存储在中间变量中,然后调用 bar().(关闭编译器优化,以避免编译器对语句进行任何重新排序!)

The simple way is to store the results of c.foo(42) and c.foo(43) in intermediate variables first and then call bar(). (Turn off compiler optimizations to avoid any reordering of statements by the compiler !!)

auto var1 = c.foo(42);
auto var2 = c.foo(43);
bar(var1, var2);

我想这就是您必须修复该错误的方式.

I guess that is how you must have fixed the bug.

这篇关于以参数评估顺序警告UB的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆