【问题标题】:inconsistent equality of signed and unsigned after overflow in CC中溢出后有符号和无符号的不一致相等
【发布时间】:2016-03-21 23:49:19
【问题描述】:

我正在尝试测试 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 的一个已知怪癖?

【问题讨论】:

  • 这不是怪癖,而是标准行为。
  • 您没有在printf 语句中进行类似的比较:在前两个(但不是第三个示例)中,您对有符号和无符号值都使用%i(有符号整数),它打印被告知放置在堆栈上的数据。一旦到了那里,除了上下文之外,就无法判断它们是签名还是未签名。在short 的情况下,值在放入堆栈之前被提升为signed intunsigned int(因为变量类型),然后由于%i 说明符而打印为signed int

标签: c long-integer unsigned integer-overflow short


【解决方案1】:

似乎在您的编译器中,shortunsigned short 都可以转换为 int 而不会丢失信息;它们的比较是在转换后完成的(“促销”)。

促销活动在securecoding.cert.org的Usual Arithmetic Conversions部分中进行了解释

  1. 如果两个操作数的类型相同,则不再进行转换 需要。

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

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

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

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

【讨论】:

    【解决方案2】:

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

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

    对于longunsigned long 测试,您的计算机似乎有64 位长,比较执行为unsigned longlong 值转换为unsigned long 但具有相同的表示,比较是真的。

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

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

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

    【讨论】:

      猜你喜欢
      • 2011-04-23
      • 2020-06-07
      • 2011-04-09
      • 2013-04-10
      • 2021-03-15
      • 2011-10-11
      • 2012-10-27
      • 2018-09-07
      • 2015-01-24
      相关资源
      最近更新 更多