考虑以下代码:
uint16_t a = ~ ( uint16_t ) 0;
int16_t b = ~ ( int16_t ) 0;
printf (
"%d %d %d %d\n",
a == ~ ( uint16_t ) 0,
a == ( uint16_t ) ( ~ ( uint16_t ) 0 ),
b == ~ ( int16_t ) 0,
b == ( int16_t ) ( ~ ( int16_t ) 0 )
);
输出结果为:
0 1 1 1
GCC发出关于a == ~ ( uint16_t ) 0
的警告:
由于数据类型[-Wtype-limits] 的范围有限,比较始终为假
为什么按位“not”运算符尝试返回有符号值?我该如何防止这种情况?
答案 0 :(得分:9)
为什么按位“not”运算符试图返回有符号值?
因为没有运算符适用于小于int
的类型;当用作操作数时,较小的类型(如果uint16_t
超过16位,则包括int
)提升。如果原始类型的所有值都由int
表示,就像它们在这里一样,那么促销将是int
。
我该如何防止这种情况?
你不能;这就是语言的运作方式。您必须将运算符的结果转换为所需的类型,或者像初始化a
时一样隐式,或者使用强制转换显式转换。请注意,在应用~
之前,您不需要强制转换;但为了获得最大的可移植性,在执行按位逻辑时应该坚持使用无符号类型:
uint16_t a = ~0u;
printf("%d\n", a == (uint16_t)~0u); // Should print 1
答案 1 :(得分:3)
Sign是我们在位模式之上的概念。逐位不(〜)仅涉及位模式而不涉及值的符号。注明无符号值的结果是相同的。
说过看C标准:http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf(草稿版免费提供)。第6.3.1.4节,第51页:
如果int可以表示原始类型的所有值(受宽度限制,对于位域),该值将转换为int;否则,它将转换为unsigned int。这些被称为整数促销。 (58)所有其他类型的整数促销不变。
我认为这意味着,当我们实际操作它们时,char和short类型将被提升为int(或unsigned int,具体取决于大小)。这是有道理的,因为我们希望尽可能快地完成操作,因此我们应该以机器的原始大小为目标。
鉴于此,我们可以看到实际发生的事情。机器将以'int'大小执行所有操作,因为'=='和'〜'的操作数都可以放在int字段中,我假设你的机器是32位。
现在首先要看的是'a'的价值。我们取0,不是它,得到0xFFFFFFFF。我们将其赋值给uint16_t值并得到0xFFFF。当我们准备进行比较时,我们加载0xFFFF,实现值无符号并将零扩展为0x0000FFFF。对于'b'的值,一切都是相同的,除非我们读取0xFFFF进行比较时我们将其扩展为0xFFFFFFFF。现在为您的案例:
等等。