3

以下计算结果对我来说是“1”。

unsigned long iEndFrame = ((4294966336 + 1920 - 1) / 1920) + 1;

有人知道为什么吗?我以为unsigned long可以处理这个。

非常感谢你的帮助。

4

3 回答 3

14

计算右侧的值具有类型unsigned intint

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;
于 2013-10-15T21:08:37.620 回答
3

“我认为 unsigned long 可以处理这个问题。” - 我不确定你的意思。您评估的表达式中没有任何内容表明它应该使用unsigned long. 您最终用它初始化变量这一事实unsigned long对评估过程没有影响。初始化表达式的处理完全独立于此。

现在,在 C++ 语言中,无后缀十进制整数文字始终具有带符号类型。不允许编译器为表达式中使用的任何文字选择无符号类型。编译器需要使用int,long intlong long int(最后一个 - 在 C++11 中),具体取决于文字的值。允许编译器使用依赖于实现的扩展整数类型,但前提是它们是有符号的。如果所有有符号类型都太小,则程序的行为是未定义的。

如果我们假设我们正在使用具有“传统”宽度为 16、32 或 64 位的整数类型的典型现实平台,那么这里只有两种可能性

  • 如果在您的平台上所有有符号整数类型都太小而无法表示4294966336,那么您的程序具有未定义的行为。故事结局。

  • 如果至少一种有符号整数类型对 来说足够大4294966336,则不应存在计算溢出,并且您的表达式应计算为2236963

因此,对该结果的唯一真正的语言级别解释1是您遇到了未定义的行为,因为所有带符号的类型都太小而无法表示您在表达式中使用的文字。

如果在您的平台上某些有符号整数类型实际上足够大以表示4294966336(即某些类型至少有 64 位),那么结果只能通过您的编译器损坏的事实来解释。

PS 请注意,unsigned int用于评估的可能性仅存在于旧 C 语言 - C89/90 中。这将为您获得的结果产生第三个解释。但是,同样,该解释仅适用于 C89/90 编译器,不适用于 C++ 编译器或 C99 编译器。你的问题被标记为[C++]。

于 2013-10-15T21:32:13.590 回答
1

我的意思是将此作为评论,但没有足够的声誉。无论如何,我想分享这个,因为我认为 tmighty 的问题有两个组成部分,据我所知,其中一个可能没有得到完全正确的回答。

  • 首先,您需要明确您正在使用的数据类型,即使用诸如 UL 之类的后缀或显式类型转换。我认为,其他答案已经足够清楚了。
  • 其次,您需要选择足够大的数据类型。

您已经说过“我认为 unsigned long 可以处理这个问题”,其他答案似乎也证实了这一点,但据我所知 - 并且刚刚仔细检查以确保 -unsigned long可能不够大。保证至少是4294967295,这对于您的用例来说太小了。具体来说,我刚刚在 Windows 下使用 VC++ 进行了检查,编译为 32 位和 64 位都将 ULONG_MAX 定义为4294967295.

您可能需要做的是使用“ULL”后缀并使用unsigned long long,因为它的最大值似乎至少是18446744073709551615. 即使有定义unsigned long为足够大以满足您的目的的平台,我认为您可能希望使用实际上保证足够大的数据类型。

于 2013-10-15T22:37:42.470 回答