为什么 MSVC 不对有符号/无符号 == 比较发出警告?

发布于 2024-10-25 22:35:35 字数 945 浏览 5 评论 0原文

我试图理解为什么以下代码不在指定位置发出警告。

//from limits.h
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
#define INT_MAX  2147483647 /* maximum (signed) int value */
            /* = 0x7fffffff */

int a = INT_MAX;
//_int64 a = INT_MAX; // makes all warnings go away
unsigned int b = UINT_MAX;
bool c = false;

if(a < b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a > b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a <= b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a >= b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a == b) // no warning <--- warning expected here
    c = true;
if(((unsigned int)a) == b) // no warning (as expected)
    c = true;
if(a == ((int)b)) // no warning (as expected)
    c = true;

我以为这与后台推广有关,但最后两个似乎不是这么说的。

在我看来,第一个 == 比较与其他比较一样是有符号/无符号不匹配?

I'm trying to understand why the following code doesn't issue a warning at the indicated place.

//from limits.h
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
#define INT_MAX  2147483647 /* maximum (signed) int value */
            /* = 0x7fffffff */

int a = INT_MAX;
//_int64 a = INT_MAX; // makes all warnings go away
unsigned int b = UINT_MAX;
bool c = false;

if(a < b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a > b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a <= b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a >= b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a == b) // no warning <--- warning expected here
    c = true;
if(((unsigned int)a) == b) // no warning (as expected)
    c = true;
if(a == ((int)b)) // no warning (as expected)
    c = true;

I thought it was to do with background promotion, but the last two seem to say otherwise.

To my mind, the first == comparison is just as much a signed/unsigned mismatch as the others?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

小帐篷 2024-11-01 22:35:35

当比较有符号和无符号时,编译器将有符号值转换为无符号值。对于相等性来说,这并不重要,-1 == (unsigned) -1。对于其他比较很重要,例如以下情况是正确的: -1 > 2U。

编辑:参考文献:

5/9:(表达式)

许多二元运算符期望
算术或枚举操作数
类型导致转换和产量
结果类型以类似的方式。这
目的是产生一个通用类型,
这也是结果的类型。
这种模式称为通常模式
算术转换,即
定义如下:

  • 如果有一个
    操作数的类型为 long double,
    其他应转换为长
    双倍。
  • 否则,如果任一操作数
    是双倍,另一个是
    转换为双精度。
  • 否则,如果
    一个操作数是 float,另一个是 float
    应转换为浮点数。
  • 否则,积分促销
    (4.5) 应同时执行
    操作数.54)
  • 然后,如果任一操作数
    是无符号长,另一个应是
    转换为无符号长整型。
  • 否则,如果一个操作数是 long
    int 和另一个无符号 int,然后
    如果一个long int可以代表所有
    unsigned int 的值,
    unsigned int 应转换为
    长整型;否则两个操作数
    应转换为 unsigned long
    整数。
  • 否则,如果任一操作数是
    long,另一个应转换为
    长。
  • 否则,如果任一操作数
    未签名的,其​​他应为
    转换为无符号。

4.7/2:(积分转换)

如果目标类型是无符号的,
结果值是最小的
无符号整数等同于
源整数(模 2n,其中 n 是
用于表示的位数
无符号类型)。 [注:在两
补表示法,这
转换是概念性的,并且有
位模式没有变化(如果有
没有截断)。 ]

EDIT2:MSVC 警告级别

MSVC 的不同警告级别所警告的内容当然是开发人员所做的选择。在我看来,他们在有符号/无符号相等与更大/更少比较方面的选择是有意义的,当然这完全是主观的:

-1 == -1 意味着与 - 相同1 == (unsigned) -1 - 我发现这是一个直观的结果。

<代码>-1 < 2 -1 意思相同(无符号)2 - 乍一看不太直观,IMO 值得“更早”警告。

When comparing signed with unsigned, the compiler converts the signed value to unsigned. For equality, this doesn't matter, -1 == (unsigned) -1. For other comparisons it matters, e.g. the following is true: -1 > 2U.

EDIT: References:

5/9: (Expressions)

Many binary operators that expect
operands of arithmetic or enumeration
type cause conversions and yield
result types in a similar way. The
purpose is to yield a common type,
which is also the type of the result.
This pattern is called the usual
arithmetic conversions, which are
defined as follows:

  • If either
    operand is of type long double, the
    other shall be converted to long
    double.
  • Otherwise, if either operand
    is double, the other shall be
    converted to double.
  • Otherwise, if
    either operand is float, the other
    shall be converted to float.
  • Otherwise, the integral promotions
    (4.5) shall be performed on both
    operands.54)
  • Then, if either operand
    is unsigned long the other shall be
    converted to unsigned long.
  • Otherwise, if one operand is a long
    int and the other unsigned int, then
    if a long int can represent all the
    values of an unsigned int, the
    unsigned int shall be converted to a
    long int; otherwise both operands
    shall be converted to unsigned long
    int.
  • Otherwise, if either operand is
    long, the other shall be converted to
    long.
  • Otherwise, if either operand
    is unsigned, the other shall be
    converted to unsigned.

4.7/2: (Integral conversions)

If the destination type is unsigned,
the resulting value is the least
unsigned integer congruent to the
source integer (modulo 2n where n is
the number of bits used to represent
the unsigned type). [Note: In a two’s
complement representation, this
conversion is conceptual and there is
no change in the bit pattern (if there
is no truncation). ]

EDIT2: MSVC warning levels

What is warned about on the different warning levels of MSVC is, of course, choices made by the developers. As I see it, their choices in relation to signed/unsigned equality vs greater/less comparisons make sense, this is entirely subjective of course:

-1 == -1 means the same as -1 == (unsigned) -1 - I find that an intuitive result.

-1 < 2 does not mean the same as -1 < (unsigned) 2 - This is less intuitive at first glance, and IMO deserves an "earlier" warning.

恋竹姑娘 2024-11-01 22:35:35

以下示例演示了为什么签名/未签名警告很重要并且程序员必须注意它们。

猜猜这段代码的输出是什么?

#include <iostream>

int main() {
        int i = -1;
        unsigned int j = 1;
        if ( i < j ) 
            std::cout << " i is less than j";
        else
            std::cout << " i is greater than j";

        return 0;
}

输出:

i is greater than j

惊讶吗?在线演示:http://www.ideone.com/5iCxY

底线:相比之下,如果有的话操作数是无符号,则另一个操作数将隐式转换为无符号如果其类型是有符号的!

Why signed/unsigned warnings are important and programmers must pay heed to them, is demonstrated by the following example.

Guess the output of this code?

#include <iostream>

int main() {
        int i = -1;
        unsigned int j = 1;
        if ( i < j ) 
            std::cout << " i is less than j";
        else
            std::cout << " i is greater than j";

        return 0;
}

Output:

i is greater than j

Surprised? Online Demo : http://www.ideone.com/5iCxY

Bottomline: in comparison, if one operand is unsigned, then the other operand is implicitly converted into unsigned if its type is signed!

百善笑为先 2024-11-01 22:35:35

从 C++20 开始,我们有特殊的函数来正确比较有符号和无符号值
https://en.cppreference.com/w/cpp/utility/intcmp

Starting from C++20 we have special functions for correct comparing signed-unsigned values
https://en.cppreference.com/w/cpp/utility/intcmp

稳稳的幸福 2024-11-01 22:35:35

== 运算符只是进行按位比较(通过简单的除法来查看是否为 0)。

较小/较大的比较更多地依赖于数字的符号。

4 位示例:

1111 = 15 ?或-1?

所以如果你有 1111 < 0001 ...这是不明确的...

但如果你有 1111 == 1111 ...这是同一件事,尽管你不是故意的。

The == operator just does a bitwise comparison (by simple division to see if it is 0).

The smaller/bigger than comparisons rely much more on the sign of the number.

4 bit Example:

1111 = 15 ? or -1 ?

so if you have 1111 < 0001 ... it's ambiguous...

but if you have 1111 == 1111 ... It's the same thing although you didn't mean it to be.

奢欲 2024-11-01 22:35:35

在使用 2 补码(大多数现代处理器)表示值的系统中,即使采用二进制形式,它们也是相等的。这可能就是编译器不会抱怨 a == b 的原因。

对我来说,奇怪的是编译器不会在 a == ((int)b) 上警告你。我认为它应该给你一个整数截断警告或其他东西。

In a system that represents the values using 2-complement (most modern processors) they are equal even in their binary form. This may be why compiler doesn't complain about a == b.

And to me it's strange compiler doesn't warn you on a == ((int)b). I think it should give you an integer truncation warning or something.

把梦留给海 2024-11-01 22:35:35

有问题的代码行不会生成 C4018 警告,因为 Microsoft 使用了不同的警告号(即 C4389) 来处理这种情况,并且默认情况下不启用 C4389(即级别 3)。

来自 C4389 的 Microsoft 文档

// C4389.cpp
// compile with: /W4
#pragma warning(default: 4389)

int main()
{
   int a = 9;
   unsigned int b = 10;
   if (a == b)   // C4389
      return 0;
   else
      return 0;
};

其他答案已经很好地解释了为什么 Microsoft 可能决定将相等运算符作为特殊情况,但我发现如果不提及 C4389 或 < a href="https://stackoverflow.com/questions/4151908/enable-a-single-warning-in-visual-studio">如何在 Visual Studio 中启用它。

我还应该提到,如果您要启用 C4389,您也可以考虑启用 C4388。不幸的是,C4388 没有官方文档,但它似乎出现在如下表达式中:

int a = 9;
unsigned int b = 10;
bool equal = (a == b); // C4388

The line of code in question does not generate a C4018 warning because Microsoft have used a different warning number (i.e. C4389) to handle that case, and C4389 is not enabled by default (i.e. at level 3).

From the Microsoft docs for C4389:

// C4389.cpp
// compile with: /W4
#pragma warning(default: 4389)

int main()
{
   int a = 9;
   unsigned int b = 10;
   if (a == b)   // C4389
      return 0;
   else
      return 0;
};

The other answers have explained quite well why Microsoft might have decided to make a special case out of the equality operator, but I find those answers are not super helpful without mentioning C4389 or how to enable it in Visual Studio.

I should also mention that if you are going to enable C4389, you might also consider enabling C4388. Unfortunately there is no official documentation for C4388 but it seems to pop up in expressions like the following:

int a = 9;
unsigned int b = 10;
bool equal = (a == b); // C4388
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文