我正在编写doctest库,它应该是无警告的。
我最近注意到,在没有警告的情况下进入if
语句的代码在我的CHECK()
宏中编写时会引起麻烦。
例如:if(0u == 0)
不引起警告,而CHECK(0u == 0);
引起警告。
我调查了一下,部分原因是CHECK()
宏背后有模板和表达式分解以及通过const引用捕获。
我的问题是:
- 给定这3个片段-为什么会发生这种情况?
给出警告:
int a = 0;
unsigned b = 0;
if(a == b)
不给出警告:
const int a = 0;
const unsigned b = 0;
if(a == b)
给出警告:
const int& a = 0;
const unsigned& b = 0;
if(a == b)
- 我该如何解决这个问题?显然,我可以在库头的模板周围使用
#pragma diagnostic
并沉默这些警告,但这将是不正确的。 - 是否有什么我错过了关于const noref的情况?因为昨天我发布了这个问题,看起来非常相似…是否还有其他的情况会因为模板中的const引用捕获而让我头疼呢?
原因是如果下面的代码给出一个警告:
int a = 0;
unsigned b = 0;
if(a == b)
那么下一段代码也应该给出一个警告:
int a = 0;
unsigned b = 0;
CHECK(a == b);
我不认为编译器或优化级别的问题-我已经尝试了几个版本的g++/MSVC (/W4
的MSVC和-Wall -Wextra -pedantic
+ 50以上的g++),可能clang做同样的…
下面的代码在g++中产生了一个警告,但在msvc中没有…(-Wsign-conversion
)
const int a = -1;
const unsigned b = 0;
if(a == b)
通常unsigned int
可以表示比int
更大的值。虽然可以将unsigned int
转换为int
,但在某些情况下会失败。例如,在2补码表示法中,-1被转换为unsigned int
中最大的数字(假设两者都使用相同大小的容器/寄存器)。
注意,当你使用const来引用时,这是正确的,因为一些引用可以在运行时初始化。例如,当你说一个函数的参数中有const引用时。只有在调用时才知道它的值。
另一方面,const int
或const unsigned int
的值在编译时是已知的。编译器知道如何从另一个转换,并且没有副作用,所以不需要警告。
如何应对这种情况?只要使用它们之间相等的类型。如果您确实想使用不同的类型并了解其副作用,您可以告诉编译器您知道自己在做什么,并执行强制类型转换(static_cast)。
在比较两个变量时得到警告是完全正常的,一个有符号,一个无符号。对于常量则不同:
这段代码没有给出警告,因为a
和b
是在编译时求值的,并且都被0替换。
将这段代码编译:
const int a = 0;
const unsigned b = 0;
if(a == b)
{
c =15;
}
else
{
c=67;
}
cout << c << endl;
a==b
部分周围拆卸:
if(a == b)
{
c=15;
1d: c7 45 f4 0f 00 00 00 movl $0xf,-0xc(%rbp)
else
{
c = 67;
}
cout << c << endl;
跳过测试,跳过else
…为什么编译器会发出警告?
此行为有时被开发人员用来禁用部分代码:在航空业务中,不可访问的代码是被禁止的。该机制确保不生成任何代码。审计可以证明在机器码级别没有死代码。