以下代码会在GCC和Clang上生成警告:
int main() {
unsigned n = 0;
return ( n < 0 ) ? 1 : 0;
}
警告是:
$ g++-4.7 -std=c++11 -O3 -Wall -Wextra t.cc -o t
t.cc: In function ‘int main()’:
t.cc:3:16: warning: comparison of unsigned expression < 0 is always false [-Wtype-limits]
$ clang++-3.2 -std=c++11 -O3 -Wall -Wextra t.cc -o t
t.cc:3:14: warning: comparison of unsigned expression < 0 is always false [-Wtautological-compare]
return ( n < 0 ) ? 1 : 0;
~ ^ ~
1 warning generated.
$
到目前为止,这么好。现在我将变量更改为const
:
int main() {
const unsigned n = 0;
return ( n < 0 ) ? 1 : 0;
}
两个编译器都很高兴在没有警告的情况下编译代码:
$ g++-4.7 -std=c++11 -O3 -Wall -Wextra t.cc -o t
$ clang++-3.2 -std=c++11 -O3 -Wall -Wextra t.cc -o t
$
问题:为什么会这样?是否存在原因,为什么const
个变量会抑制警告?如果GCC和Clang都同意,我会毫不犹豫地向他们发送错误报告,因为我似乎更有可能需要学习一些东西:)
编辑:编译器的常量折叠可能与它有关,但不足以解释行为。在第一个示例中(没有const
),编译器确实知道该值并且它永远不会更改。我检查了汇编程序输出,编译器确实进行了常量折叠,但是仍然生成警告,可能是之前它在看到表达式{{{}时用已知常量替换变量1}}并且知道( n < 0 )
是无符号类型。这就是说:当我添加n
时,为什么这种行为会发生变化?我认为如果第一个例子产生警告,也应该可以为第二个例子生成警告。
答案 0 :(得分:4)
这是一个明确的常量 - 你的意图。您所需的警告有效地从以下地址转移:
warning: comparison of unsigned expression < 0 is always false [-Wtautological-compare]
return ( n < 0 ) ? 1 : 0;
~ ^ ~
-Wunreachable-code
时到const
:
warning: will never be executed [-Wunreachable-code]
return ( n < 0 ) ? 1 : 0;
^
注意:编译器可能仍会发出-Wtautological-compare
警告,其中值未知。
答案 1 :(得分:2)
当变量不是const
时,它可能会改变,编译器不知道它。这就是警告的原因。如果是const
,它将永远不会改变。这样,编译器可以用n
的实际值替换n
的任何出现,在这种情况下:
return ( 0 < 0 ) ? 1 : 0;
-> return 0;
因此,没有警告。