为什么模运算返回意外值
Why is a modulo operation returning an unexpected value
为什么下面的代码会打印255
?
#include <stdint.h>
#include <stdio.h>
int main(void) {
uint8_t i = 0;
i = (i - 1) % 16;
printf("i: %d\n", i);
return 0;
}
我假定 15
,尽管 i - 1
的计算结果为整数。
这是因为 -1 % n
会 return -1
而不是 n - 1
1。由于本例中的 i
是无符号 8 位整数,因此它变为 255。
1 有关更多详细信息,请参阅此问题 关于负整数的模如何在 C/C+ 中工作+.
因为 C 标准中的 integer promotions。简而言之:任何类型 "smaller" 而不是 int
在使用前都被转换为 int
。一般来说,你无法避免这种情况。
那么接下来的事情是: i
晋升为 int
。表达式计算为 int
(您使用的常量也是 int
)。模数为 -1
。然后通过赋值将其转换为 uint8_t
: 255
。
对于 printf
,然后 i
被整数提升为 int
(再次):(int)255
。不过,这也没什么坏处。
注意在C89中,对于a < 0
,a % b
不一定是负数。它是实现定义的,可能是 15
。但是,自 C99 以来,-1 % 16
保证为 -1
,因为除法必须产生 代数商 .
如果要确保模数给出正结果,则必须通过强制转换 i
:
来评估整个表达式 unsigned
i = ((unsigned)i - 1) % 16;
建议:启用编译器警告。至少作业的转换应该给出截断警告。
这适用于(显示 15)Microsoft C 编译器(没有 stdint.h,所以我使用了 typedef):
#include <stdio.h>
typedef unsigned char uint8_t;
int main(void) {
uint8_t i = 0;
i = (uint8_t)(i - 1) % 16;
printf("i: %d\n", i);
return 0;
}
255 的原因是因为 (i - 1) 被提升为整数,并且 C 中用于 % 的整数除法向零舍入而不是负无穷大(向负无穷大舍入是它在数学中完成的方式、科学和其他编程语言)。因此,对于 C % 为零或与被除数具有相同的符号(在本例中为 -1%16 == -1),而在数学中模为零或与除数具有相同的符号。
为什么下面的代码会打印255
?
#include <stdint.h>
#include <stdio.h>
int main(void) {
uint8_t i = 0;
i = (i - 1) % 16;
printf("i: %d\n", i);
return 0;
}
我假定 15
,尽管 i - 1
的计算结果为整数。
这是因为 -1 % n
会 return -1
而不是 n - 1
1。由于本例中的 i
是无符号 8 位整数,因此它变为 255。
1 有关更多详细信息,请参阅此问题 关于负整数的模如何在 C/C+ 中工作+.
因为 C 标准中的 integer promotions。简而言之:任何类型 "smaller" 而不是 int
在使用前都被转换为 int
。一般来说,你无法避免这种情况。
那么接下来的事情是: i
晋升为 int
。表达式计算为 int
(您使用的常量也是 int
)。模数为 -1
。然后通过赋值将其转换为 uint8_t
: 255
。
对于 printf
,然后 i
被整数提升为 int
(再次):(int)255
。不过,这也没什么坏处。
注意在C89中,对于a < 0
,a % b
不一定是负数。它是实现定义的,可能是 15
。但是,自 C99 以来,-1 % 16
保证为 -1
,因为除法必须产生 代数商 .
如果要确保模数给出正结果,则必须通过强制转换 i
:
unsigned
i = ((unsigned)i - 1) % 16;
建议:启用编译器警告。至少作业的转换应该给出截断警告。
这适用于(显示 15)Microsoft C 编译器(没有 stdint.h,所以我使用了 typedef):
#include <stdio.h>
typedef unsigned char uint8_t;
int main(void) {
uint8_t i = 0;
i = (uint8_t)(i - 1) % 16;
printf("i: %d\n", i);
return 0;
}
255 的原因是因为 (i - 1) 被提升为整数,并且 C 中用于 % 的整数除法向零舍入而不是负无穷大(向负无穷大舍入是它在数学中完成的方式、科学和其他编程语言)。因此,对于 C % 为零或与被除数具有相同的符号(在本例中为 -1%16 == -1),而在数学中模为零或与除数具有相同的符号。