看这段代码片段:
int main()
{
unsigned int a = 1000;
int b = -1;
if (a>b) printf("A is BIG! %d\n", a-b);
else printf("a is SMALL! %d\n", a-b);
return 0;
}
这将输出: a is SMALL: 1001
我不理解这里发生了什么。大于号运算符是如何工作的?为什么"a"小于"b"?如果确实较小,为什么我得到一个正数(1001)作为差异?
看这段代码片段:
int main()
{
unsigned int a = 1000;
int b = -1;
if (a>b) printf("A is BIG! %d\n", a-b);
else printf("a is SMALL! %d\n", a-b);
return 0;
}
这将输出: a is SMALL: 1001
我不理解这里发生了什么。大于号运算符是如何工作的?为什么"a"小于"b"?如果确实较小,为什么我得到一个正数(1001)作为差异?
不同整数类型之间的二进制操作是在所谓的“常规算术转换”(参见语言规范6.3.1.8)定义的“常规”类型中执行的。在您的情况下,“常规”类型是unsigned int
。这意味着int
操作数(您的b
)将在比较之前转换为unsigned int
,并且为执行减法而进行转换。
当-1
转换为unsigned int
时,结果是最大可能的unsigned int
值(与UINT_MAX
相同)。不用说,它将大于您的无符号1000
值,这意味着a>b
确实是假的,并且a
确实与(unsigned) b
相比较小。您代码中的if
应该解析为else
分支,这就是您在实验中观察到的。
减法使用相同的转换规则。您的a-b
实际上被解释为a - (unsigned) b
,其结果类型为unsigned int
。这样的值不能用%d
格式说明符打印,因为%d
仅适用于有符号的值。您尝试使用%d
将其打印出来会导致未定义的行为,因此从C语言的角度来看,您看到的打印值(即使在实践中它有一个逻辑上确定的解释)是完全无意义的。
编辑:实际上,我可能对未定义的行为部分错误。根据C语言规范,相应有符号和无符号整数类型的公共部分应具有相同的表示形式(暗示着“作为函数参数的互换性”)。因此,a-b
表达式的结果是无符号的1001
,如上所述,除非我遗漏了什么,否则使用%d
说明符打印此特定的无符号值是合法的,因为它落在正int
的范围内。使用%d
打印(unsigned) INT_MAX + 1
将是未定义的,但1001u
没问题。
va_arg(ap, int)
是没有 UB 的。但是,如果违反 printf 对预期 int
的要求,则确实会产生 UB。尽管对我来说这听起来很愚蠢。为什么他们没有为 printf 指定:“下一个参数的类型应为有符号或无符号整数,并应在 int 范围内”。 - Johannes Schaub - litbfprintf
的描述如下:(对于%d):“将int参数转换为...”,以及“如果任何参数与相应的转换规范不匹配,行为是未定义的。” 所以我不认为它是明确定义的。也许usenet 上的某个人知道? - Johannes Schaub - litbx = 10 +- 10u + 10u +- 10;
?无论x是有符号还是无符号,结果都相同! - mikeint
为32位时,将-1转换为 unsigned int
得到的结果是4,294,967,295,确实≥1000。1000 - (4,294,967,295) = -4,294,966,295 = 1,001
这就是你得到的结果。gcc
会发出警告。(如果没有看到警告,请传递 -Wsign-compare
标志。)UINT_MAX
是 4,294,967,295。另请参见 https://dev59.com/d3I-5IYBdhLWcg3wbHq-。 - Alok Singhal #include<stdio.h>
int main()
{
int a = 1000;
signed int b = -1, c = -2;
printf("%d",(unsigned int)b);
printf("%d\n",(unsigned int)c);
printf("%d\n",(unsigned int)a);
if(1000>-1){
printf("\ntrue");
}
else
printf("\nfalse");
return 0;
}
为此,您需要了解运算符的优先级
关系运算符从左到右工作... 所以当它遇到
if(1000>-1)
首先将-1更改为无符号整数,因为默认情况下int被视为无符号数字,并且其范围大于有符号数字
-1将更改为无符号数字,它会变成一个非常大的数字
你正在进行无符号比较,即将1000与2^32 - 1进行比较。
由于printf中的%d,输出是有符号的。
注意:当混合使用有符号和无符号操作数时,行为有时取决于编译器。我认为最好避免它们,并在怀疑时进行强制转换。
int
和 unsigned int
操作数之间的减法被计算为无符号减法,结果当然是无符号的。 - AnT stands with Russia找到一种简单的比较方法,当你无法摆脱无符号声明时可能会有用(例如,[NSArray count]),只需将“unsigned int”强制转换为“int”。
如果我错了,请纠正我。
if (((int)a)>b) {
....
}