【发布时间】:2015-05-24 14:50:27
【问题描述】:
使用 GCC:
printf("%i \n", -1 % (int)4);
printf("%u \n", -1 % (unsigned int)4);
输出:
-1
3
我可以跨平台依赖这种行为吗?我是否应该明确定义 MOD 和 REM 宏以确保不会更改?
【问题讨论】:
标签: c rounding modulo behavior floor-division
使用 GCC:
printf("%i \n", -1 % (int)4);
printf("%u \n", -1 % (unsigned int)4);
输出:
-1
3
我可以跨平台依赖这种行为吗?我是否应该明确定义 MOD 和 REM 宏以确保不会更改?
【问题讨论】:
标签: c rounding modulo behavior floor-division
模运算符 (%) 多年来一直是 C 和 C++ 标准的一部分。我不确定您是否可以在 C++ 中重载它。所以是的,你可以依赖它。
【讨论】:
% 运算符。并且您不能重载 C 中的任何运算符。他询问负数的行为
从 C99 开始,% 的结果需要向 0 舍入,正如 Chris Dodd 所引用的那样。
在 C99 标准之前,% 运算符对负数的行为是实现定义的。
当整数被除且除法不精确时,如果两个操作数都是正数,
/运算符的结果是小于代数商的最大整数,%运算符的结果是正数。 如果任一操作数为负数,/运算符的结果是小于代数商的最大整数还是大于代数商的最小整数是实现定义的 >,就像%运算符的结果的符号一样。如果商a/b是可表示的,则表达式(a/b)*b + a%b应等于a。
因此,如果您的目标是 C99 或更高版本,则结果是 Yes,否则您不能依赖它。
如果您需要可移植到更旧的 C 标准的一致结果,您可以使用 div or ldiv,无需定义自己的 MOD 和 REM
C99 rationale regarding div, ldiv, and lldiv functions:
因为当涉及负操作数时,C89 具有实现定义的有符号整数除法语义,所以发明了 div 和 ldiv 以及 C99 中的 lldiv 来为有符号整数除法和余数运算提供明确指定的语义。
【讨论】:
C99 标准说:
6.5.5 乘法运算符
:
当整数被除法时,/ 运算符的结果是任何一个的代数商 小数部分被丢弃87)。如果商 a/b 是可表示的,则表达式
(a/b)*b + a%b 应等于 a。
:
87) 这通常被称为“向零截断”
这意味着除法总是向 0 舍入,所以你可以依赖它。
请注意,这与 C++03 标准不同。
您的第二行执行无符号除法,将值 -1 转换为除法之前的 unsigned int。这总是比 2 的幂小一,所以这也是很好定义的。
【讨论】:
(unsigned int) 演员表的存在会将所有其他常量转换为无符号整数,-1s 将变得很大正整数(小于 2 的幂)
% 的 C99 行为,尽管标准允许更大的灵活性,但大多数实现都是一致的.
-std=c99,因为有些编译器默认不启用C99。这不适用于旧编译器