以下计算结果为“1”。
unsigned long iEndFrame = ((4294966336 + 1920 - 1) / 1920) + 1;
有人知道为什么吗?我认为unsigned long
可以解决这个问题。
非常感谢您的帮助。
答案 0 :(得分:14)
计算右侧的值包含unsigned int
或int
。
4294966336 + 1920 = 4294968256
假设sizeof(unsigned int) == 4
,这会溢出,只留下960
(960-1)/1920 = 0
(由于整数运算中的舍入)。这将离开你
0 + 1 = 1
如果您想使用更大的类型执行计算(假设sizeof(unsigned long) > sizeof(unsigned int)
),则需要在计算中进行强制转换
unsigned long iEndFrame = (((unsigned long)4294966336 + 1920 - 1) / 1920) + 1;
或者,如Slava所述,使用unsigned long
后缀设置其中一个文字值为UL
类型
unsigned long iEndFrame = ((4294966336UL + 1920 - 1) / 1920) + 1;
答案 1 :(得分:3)
“我认为unsigned long可以解决这个问题。” - 我不确定你的意思。您评估的表达式中没有任何内容表明它应该使用unsigned long
。您最终使用它初始化unsigned long
变量的事实对评估过程没有影响。初始化表达式完全独立于此处理。
现在,在C ++语言中,未加十进制的十进制整数文字总是具有 signed 类型。不允许编译器为表达式中使用的任何文字选择无符号类型。编译器需要使用int
,long int
或long long int
(最后一个 - 在C ++ 11中),具体取决于文字的值。允许编译器使用依赖于实现的扩展整数类型,但仅限于签名。如果所有签名类型都太小,程序的行为是不确定的。
如果我们假设我们正在使用典型的现实生活平台,其整数类型的宽度为“传统的”16,32或64位,那么这里只有两种可能性
如果您的平台上所有签名的整数类型都太小而无法代表4294966336
,那么您的程序会有未定义的行为。故事结束。
如果至少有一个有符号整数类型足够4294966336
,则应该没有评估溢出,并且您的表达式应该评估为2236963
。
因此,对1
结果唯一真正的语言级解释是您遇到了未定义的行为,因为所有签名类型都太小而无法表示您在表达式中使用的文字。
如果在您的平台上,某些有符号整数类型实际上足够大以表示4294966336
(即某些类型至少有64位),那么结果只能通过编译器被破坏的事实来解释。 / p>
P.S。请注意,unsigned int
用于评估的可能性仅存在于旧C语言 - C89 / 90中。这将为您获得的结果产生第三种解释。但是,同样,这种解释只适用于C89 / 90编译器,而不适用于C ++编译器或C99编译器。你的问题被标记为[C ++]。
答案 2 :(得分:1)
我的意思是将此作为评论,但没有足够的声誉。无论如何,我想分享这个,因为我认为有两个组成部分可以解决问题,其中一个可能没有得到正确解答,我理解的是。
你已经说过“我认为unsigned long可以解决这个问题”,其他答案似乎也证实了这一点,但据我所知 - 并且现在仔细检查以确保 - unsigned long
可能不会足够大。保证至少为4294967295
,这对于您的用例来说太小了。具体来说,我刚刚在Windows下使用VC ++进行了检查,并且编译为32位和64位,将ULONG_MAX定义为4294967295
。
您可能需要做的是使用“ULL”后缀并使用unsigned long long
,因为它的最大值似乎至少为18446744073709551615
。即使存在将unsigned long
定义为足够大的平台,我认为您可能希望使用实际上保证足够大的数据类型。