C中溢出后有符号和无符号的不一致相等
Posted
技术标签:
【中文标题】C中溢出后有符号和无符号的不一致相等【英文标题】:inconsistent equality of signed and unsigned after overflow in C 【发布时间】: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 int
和unsigned int
(因为变量类型),然后由于%i
说明符而打印为signed int
。
【参考方案1】:
似乎在您的编译器中,short
和 unsigned short
都可以转换为 int
而不会丢失信息;它们的比较是在转换后完成的(“促销”)。
促销活动在securecoding.cert.org的Usual Arithmetic Conversions部分中进行了解释
如果两个操作数的类型相同,则不再进行转换 需要。
如果两个操作数都是相同的整数类型(有符号或 unsigned),具有较小整数转换类型的操作数 rank 转换为具有更高等级的操作数的类型。
如果 具有无符号整数类型的操作数的秩大于或 等于另一个操作数的类型的等级,操作数与 有符号整数类型转换为操作数的类型 无符号整数类型。
如果操作数的类型带符号 整数类型可以表示该类型的所有值 无符号整数类型的操作数,无符号的操作数 整数类型转换为带符号的操作数的类型 整数类型。
否则,两个操作数都将转换为无符号数 与带符号的操作数类型对应的整数类型 整数类型。
【讨论】:
【参考方案2】:鉴于您的输出,short
和 unsigned short
小于 int
。第一次比较时两者都转换为int
,转换后的值不同。
对于int
和unsigned int
,比较执行为unsigned int
。转换给出相同的值并且比较是正确的。请注意,您应该使用适当的格式打印数字:printf("si = %i, ui = %u\n", si, ui);
对于long
和unsigned long
测试,您的计算机似乎有64 位长,比较执行为unsigned long
,long
值转换为unsigned long
但具有相同的表示,比较是真的。
请注意,您不应将大于最大值的数字存储到有符号类型中:
signed short ss = 0x8000;
不能保证将-32768
存储到ss
。
signed int si = 0x80000000;
和 signed long sl = 0x8000000000000000L;
的问题相同。
【讨论】:
以上是关于C中溢出后有符号和无符号的不一致相等的主要内容,如果未能解决你的问题,请参考以下文章