C / C++中无符号整数的减法和比较是否定义良好?

Is subtraction and comparison with unsigned integers in C / C++ well defined?

本文关键字:是否 比较 定义 C++ 无符号整数      更新时间:2023-10-16

作为对"无符号整数减法是否定义了行为?"问题的扩展,我对以下行为感到困惑。

在下面的代码中,请注意,A = 50B = 100存储为无符号 16 位整数,减法A - B = -50 = 65486 (mod 2^16 - 1)。如果我将减法的结果存储在D(一个无符号的 16 位整数)中,然后评估D > 4000我得到true,因为65486 > 4000.这是有道理的。

如果我放弃存储A - B并直接评估A - B > 4000,我会得到错误。这似乎不一致。这是预期的结果吗?为什么?这始终是正确的行为,还是我处于"未定义行为"的状态。

#include <stdio.h>
#include <stdint.h>
int main() {
uint16_t A = 50;
uint16_t B = 100;
uint16_t D = A - B;     // D = 65486                                                                                        
printf("D = %un", D);
int R = D > 4000;       // R = 1 (true)                                                                                 
printf("R = %dn", R);
int S = A - B > 4000;   // S = 0 (false)                                                                                
printf("S = %dn", S);
return 0;
}

顺便说一句,这种行为似乎与这个问题的代码中的行为相矛盾,这进一步让我感到困惑。如果我将uint16_t更改为上面的uint32_t,则得到

D = 4294967246
R = 1
S = 1

这对我来说似乎是正确的。

更新:似乎最好的详细答案是uint16_t被提升为int(int在我的系统上是 32 位),因此A - B > 4000是用有符号算术完成的。而当我切换到uint32_t时,没有执行任何提升(已经是 32 位宽),因此A - B > 4000是用无符号算术完成的。这可以解释它。

附言我知道人们想第一个回答,但仅仅说"整数提升"不是一个有用的答案。

如果我放弃存储 A - B 并直接评估 A - B> 4000,我会得到错误。这似乎不一致。

是的,粗略地看一下。

但是,当计算表达式A-B时,在执行减法之前,两者都会提升为int。因此,A - B > 5000计算结果为 false。

您可以在 http://en.cppreference.com/w/c/language/conversion 阅读"常用算术转换"。

但是当我切换到unit32_t呢:

当两个操作数都是类型unit32_t时,在sizeof(int)为 4 而不是int的平台上,结果也是类型unit32_t的。