比较对 int 和 unsigned 的引用时发出警告,但如果将 const(无引用)与 g++/msvc 进行比较则没有警告

Warning when comparing references to int and unsigned but no warning if comparing consts (no ref) with g++/msvc

所以我正在编写 doctest 库,它应该没有警告。

我最近注意到,在我的 CHECK() 宏中写入时,在没有警告的情况下进入 if 语句的代码会造成问题。

例如:if(0u == 0) 不会导致警告,但 CHECK(0u == 0); 会。

我调查了一下,部分原因是CHECK()宏背后有模板和表达式分解,并通过const引用捕获。

我的问题是3:

  1. 鉴于这 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)
  1. 我该如何解决这个问题?显然我可以在库 header 中的模板周围使用 #pragma diagnostic 并使这些警告静音,但这是不正确的。

原因是如果下面的代码给出警告:

int a = 0;
unsigned b = 0;
if(a == b)

那么下一段代码也应该给出警告:

int a = 0;
unsigned b = 0;
CHECK(a == b);
  1. 关于 const noref 案例,我是否遗漏了什么?因为昨天我发布了 问题,这个问题看起来非常相似......是否有其他情况会因为我的模板中的 const 引用捕获而咬我的屁股?

我认为编译器或优化级别不重要 - 我已经尝试了几个版本的 g++/MSVC(/W4 for msvc 和 -Wall -Wextra -pedantic + 50 more for g++) 并且 clang 可能做同样的事情...

编辑:

以下代码对 g++ 产生了警告,但对 msvc 却没有... (-Wsign-conversion)

const int a = -1;
const unsigned b = 0;
if(a == b)

比较 2 个变量时收到警告是完全正常的,一个有符号,一个无符号。 对于常量,它是不同的:

此代码不会给出警告,因为 ab 在编译时计算并都被 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   [=11=]xf,-0xc(%rbp)
else
{
        c = 67;
}
cout << c << endl;

测试被跳过,else被跳过...为什么编译器会发出警告?

这种行为有时被开发人员用来禁用部分代码:在航空业务中,禁止无法访问的代码。这种机制确保不会生成任何代码。审计可以证明机器代码级别没有死代码。

通常 unsigned int 可以表示比 int 更大的值。虽然您可以将 unsigned int 转换为 int,但在某些情况下它会失败。例如,在 2 补码表示法中,-1 被转换为 unsigned int 中的最大数(假设两者都使用相同大小的容器/寄存器)。

注意当你使用const引用时也是如此,因为有些引用可以在运行时初始化。例如,当你说一个函数在其参数中有 const 引用时。你只会在调用时知道它的值。

另一方面,const intconst unsigned int 的值在编译时已知。编译器知道如何从 which other 转换并且没有副作用,所以不需要警告。

如何应对这种情况?只需使用它们之间相等的类型。如果你真的想使用不同的类型并且知道副作用,你可以告诉编译器你知道你在做什么并进行转换(static_cast)。