所以我正在编写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
并使这些警告静音但这不正确。原因是如果以下代码发出警告:
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 more用于g ++)并且可能clang做同样的事情......
修改
以下代码使用g ++生成警告,但未使用msvc ... {-Wsign-conversion
)
const int a = -1;
const unsigned b = 0;
if(a == b)
答案 0 :(得分:1)
在比较2个变量时,得到警告是完全正常的,一个是有符号的,一个是无符号的。 对于常数,它是不同的:
此代码不会发出警告,因为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
...为什么编译器会发出警告?
开发人员有时会使用此行为来禁用部分代码:在航空业务中,禁止无法访问的代码。此机制确保不生成任何代码。审计可以证明机器代码级别没有死代码。
答案 1 :(得分:1)
通常unsigned int
可以表示比int
更大的值。虽然您可以将unsigned int
转换为int
,但有时会失败。例如,在2补码表示法中,-1被转换为unsigned int
中的最大数字(假设两者都使用相同大小的容器/寄存器)。
请注意,当您使用const引用时,这是正确的,因为某些引用可以在运行时初始化。例如,当你说一个函数在其参数中有const引用时。你只会在通话时知道它的价值。
另一方面,const int
或const unsigned int
在编译时已知其值。编译器知道如何转换来自哪个并且没有副作用,因此不需要警告。
如何对抗这种情况?只需使用它们之间相同的类型。如果你真的想使用不同的类型并知道副作用,你可以告诉编译器你知道你在做什么并做一个演员(static_cast)。