C中溢出后有符号和无符号的不一致相等

inconsistent equality of signed and unsigned after overflow in C

我正在尝试在 C 中测试 short、int 和 long 的有符号和无符号版本的相等性。特别是,我使用了以下测试代码:

#include <stdio.h>

int main() {
    signed short ss = 0x8000; // 2^15
    unsigned short us = 0x8000;
    printf("ss = %i, us = %i\n", ss, us);
    if (ss == us) { printf("ss == us\n"); }
    else { printf("ss != us\n"); }

    signed int si = 0x80000000; // 2^31
    unsigned int ui = 0x80000000;
    printf("si = %i, ui = %i\n", si, ui);
    if (si == ui) { printf("si == ui\n"); }
    else { printf("si != ui\n"); }

    signed long sl = 0x8000000000000000L; // 2^63
    unsigned long ul = 0x8000000000000000UL; // 2^63
    printf("sl = %li, ul = %lu\n", sl, ul);
    if (sl == ul) { printf("si == ui\n"); }
    else { printf("sl != ul\n"); }
}

代码输出如下:

ss = -32768, us = 32768
ss != us
si = -2147483648, ui = -2147483648
si == ui
sl = -9223372036854775808, ul = 9223372036854775808
si == ui

所以对于短裤来说它们是不相等的,但是对于另外两个它们是相等的。我的假设有什么问题吗,或者这只是 C 的一个已知怪癖?

看来在您的编译器中,shortunsigned short 都可以转换为 int 而不会丢失信息;它们的比较是在转换后完成的 ("promotion")。

促销活动在 securecoding.cert.org

Usual Arithmetic Conversions 部分进行了说明
  1. 如果两个操作数的类型相同,则不进行进一步的转换 需要。

  2. 如果两个操作数是相同的整数类型(有符号或 无符号),具有较小整数转换类型的操作数 rank 转换为具有更高 rank 的操作数的类型。

  3. 如果 具有无符号整数类型的操作数的等级大于或 等于另一个操作数类型的等级,操作数与 有符号整数类型转换为操作数的类型 无符号整数类型。

  4. 如果操作数的类型有符号 整数类型可以表示该类型的所有值 无符号整数类型的操作数,无符号的操作数 整数类型转换为带符号的操作数类型 整数类型。

  5. 否则,两个操作数都转换为无符号数 与带符号的操作数类型对应的整数类型 整数类型.

鉴于您的输出,shortunsigned short 小于 int。两者都转换为 int 进行第一次比较,转换后的值不同。

对于intunsigned int,比较按unsigned int进行。转换给出相同的值并且比较为真。请注意,您应该以适当的格式打印数字:printf("si = %i, ui = %u\n", si, ui);

对于longunsigned long的测试,你的电脑好像是64位的long,比较的是unsigned long,把long的值转换成一个 unsigned long 但具有相同的表示,比较再次为真。

请注意,您不应将大于最大值的数字存储到有符号类型中:

signed short ss = 0x8000;不保证将-32768存储到ss

signed int si = 0x80000000;signed long sl = 0x8000000000000000L; 的相同问题。