【发布时间】:2014-04-02 13:07:07
【问题描述】:
以下示例中的if 语句来自我正在尝试再次构建的一个旧项目。很抱歉,这不是一个可验证的示例,因为它不会重现错误,它可以自行编译。
enum S { };
struct R {
S type, state;
double height;
};
int main ()
{
int rows;
S alive, rc;
double h;
R *r, *n;
// BEGIN
if ( (((r = n-1) ->type & rc) && h > r->height) ||
(((r = n+1) ->type & rc) && h > r->height) ||
(((r = n-rows)->type & rc) && h > r->height) ||
(((r = n+rows)->type & rc) && h > r->height) )
{
n->state = alive;
}
// END
}
但是,在项目中,使用相同的编译(clang 3.3,除了包含路径之外没有其他选项),它给出了
warning: multiple unsequenced modifications to 'r' [-Wunsequenced]
(指向子表达式r = n - 1)。 if 语句(标记在BEGIN-END 之间)在项目中是相同的,只是变量的类型可能不同。这里定义的类型只是粗略的近似,但我认为它们与警告并不真正相关。我已经能够将表达式简化为
if( (r = n) || (r = n) ) //...
同时仍在项目中重现警告。
我的理解是,运算符&&、||(未重载时)的第一个操作数求值后有一个序列点。所以我无法解释这个警告。
如果对表达式的形式有任何想法,无论类型如何,那都会有所帮助。
编辑
使用 Vaughn Cato 的 cmets,我也发现
if( ((r = n-1) ->type) || ((r = n+1) ->type) )
产生警告,而
if( bool((r = n-1) ->type) || bool((r = n+1) ->type) )
没有。 S 实际上是一个模仿枚举的类,并且有一个自定义的底层类。它重载了位运算符&、| 和! 用于掩码,以及隐式转换运算符到底层类型,在特定情况下为size_t。我不知道这有多大帮助,但很抱歉没有从一开始就披露更完整的信息。
【问题讨论】:
-
所涉及的类型是否可以有用户定义的运算符
&&和||?只有内置的操作符有顺序保证。 -
只有
operator&被重载,但即使在没有&的简化表达式中,警告仍然存在。此外,r,n是指针,所以我认为我不能重载其他任何东西。 -
+1:这是一个很深的问题。我已将答案扔进戒指,但有兴趣等待更详细的回复。
-
项目中
r的类型也是原始指针吗? -
请注意,现在 安全点 的概念已被弃用,取而代之的是定义良好的标准多线程内存模型。
标签: c++ logical-operators sequence-points