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 的一个已知怪癖?
看来在您的编译器中,short
和 unsigned short
都可以转换为 int
而不会丢失信息;它们的比较是在转换后完成的 ("promotion")。
促销活动在 securecoding.cert.org
的 Usual Arithmetic Conversions 部分进行了说明
如果两个操作数的类型相同,则不进行进一步的转换
需要。
如果两个操作数是相同的整数类型(有符号或
无符号),具有较小整数转换类型的操作数
rank 转换为具有更高 rank 的操作数的类型。
如果
具有无符号整数类型的操作数的等级大于或
等于另一个操作数类型的等级,操作数与
有符号整数类型转换为操作数的类型
无符号整数类型。
如果操作数的类型有符号
整数类型可以表示该类型的所有值
无符号整数类型的操作数,无符号的操作数
整数类型转换为带符号的操作数类型
整数类型。
否则,两个操作数都转换为无符号数
与带符号的操作数类型对应的整数类型
整数类型.
鉴于您的输出,short
和 unsigned short
小于 int
。两者都转换为 int
进行第一次比较,转换后的值不同。
对于int
和unsigned int
,比较按unsigned int
进行。转换给出相同的值并且比较为真。请注意,您应该以适当的格式打印数字:printf("si = %i, ui = %u\n", si, ui);
对于long
和unsigned long
的测试,你的电脑好像是64位的long,比较的是unsigned long
,把long
的值转换成一个 unsigned long
但具有相同的表示,比较再次为真。
请注意,您不应将大于最大值的数字存储到有符号类型中:
signed short ss = 0x8000;
不保证将-32768
存储到ss
。
signed int si = 0x80000000;
和 signed long sl = 0x8000000000000000L;
的相同问题。
我正在尝试在 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 的一个已知怪癖?
看来在您的编译器中,short
和 unsigned short
都可以转换为 int
而不会丢失信息;它们的比较是在转换后完成的 ("promotion")。
促销活动在 securecoding.cert.org
的 Usual Arithmetic Conversions 部分进行了说明如果两个操作数的类型相同,则不进行进一步的转换 需要。
如果两个操作数是相同的整数类型(有符号或 无符号),具有较小整数转换类型的操作数 rank 转换为具有更高 rank 的操作数的类型。
如果 具有无符号整数类型的操作数的等级大于或 等于另一个操作数类型的等级,操作数与 有符号整数类型转换为操作数的类型 无符号整数类型。
如果操作数的类型有符号 整数类型可以表示该类型的所有值 无符号整数类型的操作数,无符号的操作数 整数类型转换为带符号的操作数类型 整数类型。
否则,两个操作数都转换为无符号数 与带符号的操作数类型对应的整数类型 整数类型.
鉴于您的输出,short
和 unsigned short
小于 int
。两者都转换为 int
进行第一次比较,转换后的值不同。
对于int
和unsigned int
,比较按unsigned int
进行。转换给出相同的值并且比较为真。请注意,您应该以适当的格式打印数字:printf("si = %i, ui = %u\n", si, ui);
对于long
和unsigned long
的测试,你的电脑好像是64位的long,比较的是unsigned long
,把long
的值转换成一个 unsigned long
但具有相同的表示,比较再次为真。
请注意,您不应将大于最大值的数字存储到有符号类型中:
signed short ss = 0x8000;
不保证将-32768
存储到ss
。
signed int si = 0x80000000;
和 signed long sl = 0x8000000000000000L;
的相同问题。