什么是“int i = 1;为什么(i> = 60 * 60 * 1000/1 * 1000)”是真的?
首先,定义两个没有括号的常量expression式是我的错:
#define BIG_INTERVAL 60 * 60 * 1000 #define SMALL_INTERVAL 1 * 1000 int i = 1; if (i >= BIG_INTERVAL / SMALL_INTERVAL - 1) { printf("Oops!\n"); }
macros展开后的if
语句是if(i >= 60 * 60 * 1000 / 1 * 1000 - 1)
。
那不是我的意图。 但是如果我写if (i >= 3600000000 - 1)
我会发现一些奇怪的东西。 这是错误的。
什么types是60 * 60 * 1000 / 1 * 1000 - 1
? int
?
int
的所有运算符都返回int
。 所以是的, 60 * 60 * 1000 / 1 * 1000 - 1
是一个int
。 但3599999999的预期结果对于int
来说太大了,所以expression式实际上是-694967297(假设32位int
和2的补码)。
这不会发生在文字INT_MAX
,因为大于INT_MAX
整数文字是可以保存完整值的types。
60 * 60 * 1000/1 * 1000 – 1 = 3600000 * 1000 – 1,它溢出inttypes,所以结果可以是任何东西(在你的情况下,它是负的,但不一定)。
要实现你想要的东西():
#define BIG_INTERVAL (60 * 60 * 1000) #define SMALL_INTERVAL (1 * 1000)
这是我的testing结果:
60 * 60 * 1000 / 1 * 1000 will result to -694967296 (60 * 60 * 1000) / (1*1000) will result to 3600
你的操作存在一个问题,即计算的优先级。
您可能要考虑查看C ++运算符的优先顺序http://msdn.microsoft.com/en-us/library/126fe14k%28v=vs.80%29.aspx 。 你会发现结果变成-694967296的原因,我觉得溢出的效果。
如果在int为64位时使用编译器,则会发现expression式的结果为false。 如果使用int为32位或16位的编译器,则expression式具有未定义的行为,因为signed int的溢出不必环绕。 也许你的确只是环绕一下,但并不是必须的。
3600000000是在编译时可见的常量,所以如果int只有32位,那么编译器将不得不selectlong long(或long long,如果long是64位)。 所以你的其他expression式用足够的位来评估,以避免溢出,结果是正确的。
可能是因为你满足了2147米左右的整数大小,这意味着如果你越过这个表示就变成了负数。 正如其他答案所指出的那样,分割在扩展的时候什么也不做,所以用括号括起macros定义
你很有可能超出有效范围的值为一个有符号整数 – 3600000000是一个相当大的数字!
发生这种情况时,该值将成为int数据types的最小负值。
这将导致你的陈述是真实的。
该expression式的每个参数都是一个整数,所以结果将是一个整数。
我想你对macros如何工作感到困惑。 您不使用这些macros的值,而是使用方程本身。 我认为这是你的困惑所在。 我认为你应该在你的macros中使用括号或不使用macros。
我还没有看到任何人提到的是,即使将macros定义完全加上括号也不能完全解决问题。
这个问题有:
#define BIG_INTERVAL 60 * 60 * 1000
(提问者承认缺less括号是一个问题)。 但即使如此:
#define BIG_INTERVAL (60 * 60 * 1000)
每个常量(60,60和1000)都可以表示为int,但产品是3600000,而语言只能保证INT_MAX >= 32767
。
该语言表示,大的整数常量是一个足够大的types来保存它们的值(例如,根据这些types的范围, 100000
可以是int
types或long int
types),但是它没有这样的规则expression式,甚至常量expression式。
你可以像这样解决这个问题:
#define BIG_INTERVAL (60L * 60L * 1000L)
但即使不需要,也可以使其long
型化。
至于运营商的优先权问题,这里是我最喜欢的例子:
#include <stdio.h> #define SIX 1+5 #define NINE 8+1 int main(void) { printf("%d * %d = %d\n", SIX, NINE, SIX * NINE); return 0; }
输出当然是
6 * 9 = 42
(见道格拉斯·亚当斯)。