急求高手指教数值溢出问题!!!!!!!!

时间:2022-09-29 23:36:29
代码如下:
#include <iostream>
int main()
{
    using namespace std;
    unsigned long max = (unsigned long) (-1);
    cout<<max<<endl;//输出为2的64次方
    unsigned long num = 6789 + 8 * 1000000000;//80多亿
    cout<<num<<endl;//
    return 0;
}
我编译器和系统都是64位的,num最后输出的结果竟然是比max小一点的值,远大于80多Y,显然是溢出了,这是为什么啊,跪求大侠帮忙分析下,先谢了

29 个解决方案

#1


不要沉了,看到的给点思路,谢谢啊

#2


关注一下,32位机没法验证。

#3


32位机也可以验证的,得到的也不是预想的80多亿,也是溢出值

#4


蛮诡异哦,你看下汇编代码看看。

#5


看到汇编就头大 我去瞅瞅

#6


g++产生的汇编和以前学的X86汇编相差太大了,还是请高手指点

#7


大家不会都忙着过端午节吧?帮忙看一下啊,我都快欲哭无泪了……

#8


说说我的想法吧
我给你举个例子吧。(我的编译器长整形是占四个字节)
按照你的编译器无符号长整形是占8个字节。
unsigned long max = (unsigned long) (-1);//此处(-1)在内存是存的是补码  全部是1(总共64个1)
                                         //在转化成无符号长整数时。那么就应该是2^64-1
  cout<<max<<endl;//理论上应该输出为2的64次方再减一

楼主不知你的是多少???       
    

#9


恩,对,我上面描述有点小错误,是2的64次方-1,照理说这样的变量被赋上10亿不应该溢出的,但是却偏偏溢出了,g++编译时还有警告,说溢出……

#10


围观中。我试试也溢出了。期待大牛的出现。

#11


这个在32位机器上也是可以验证的,linux下的话用unsigned long long,windows下用unsigned uint_64 ,结果都会溢出,有人遇到过这样的问题吗?我实际工程中出现了这种情况,百思不得其解……

#12


此时如果再定义一个同样的变量,直接赋值,就像这样:
unsigned long numTemp = 8000006789;
cout<<numTemp<<endl;//此时输出正常,就是80多亿,这是神马情况?
看了一下两者的汇编代码,相差挺大的,不过不清楚,为什么会不一样的结果,因为对AT&T汇编不熟悉……

#13


引用楼主 wangluoqingfeng 的回复:
代码如下:
#include <iostream>
int main()
{
  using namespace std;
  unsigned long max = (unsigned long) (-1);
  cout<<max<<endl;//输出为2的64次方
  unsigned long num = 6789 + 8 * 1000000000;//80多亿
  cou……

在我的电脑上unsigned long只有32位
我认为
  //8 * 1000000000已经越界了
  long long 是64

#14


我的是64位机……,上面我说了,32位机 linux下你改成unsigned long long,windows下 你改成uint_64,上面的情况可以复现的

#15


引用 14 楼 wangluoqingfeng 的回复:
我的是64位机……,上面我说了,32位机 linux下你改成unsigned long long,windows下 你改成uint_64,上面的情况可以复现的


我也是64位机子,但unsigned long就只有32位,unsigned long long 是64位的

我也有点糊涂,直接赋值(没有运算时就是对的) 如:unsigned long long num=80456485686;
但unsigned long long num = 6789 + 8 * 1000000000;还是出现错了,会出现很大的数
18446744073709551615
18446744073119623569
请按任意键继续. . .

#16


编译器默认按32位分析6789 + 8 * 1000000000,因此警告溢出。我在VC下用以下形式,编译和运行结果都正常:

#include <stdio.h>
int main()
{
  unsigned __int64 max = (unsigned __int64) (-1);
  printf("%I64u",max);
  //unsigned __int64  num = 6789 + 8 * 1000000000;//warning C4307: '*' : integral constant overflow
  unsigned __int64  num = 6789 + 8 * (unsigned __int64)1000000000;

  printf("%I64u",num);
  return 0;
}

#17


引用 16 楼 logiciel 的回复:
编译器默认按32位分析6789 + 8 * 1000000000,因此警告溢出。我在VC下用以下形式,编译和运行结果都正常:


C/C++ code
#include <stdio.h>
int main()
{
  unsigned __int64 max = (unsigned __int64) (-1);
  printf("%I64u",max);
  //unsign……


我之前也是想这么认为的,运算默认是按32位来运算了,

unsigned long long num = 6789 + 8 * 1000000000;
会输出如下结果,我知道我错了,不是按32位来运算的
18446744073119623569

#18


哦,确实是按32位来计算了,我刚又验证了下

#19


理论上max = 2^64 - 1
num为什么会溢出,你可以检查下sizeof(unsigned long)为几字节。

#20


引用 19 楼 fengqiao1999 的回复:
理论上max = 2^64 - 1
num为什么会溢出,你可以检查下sizeof(unsigned long)为几字节。


运算的时候,运算数会转为32位的数进行运算,这是8 * 1000000000的结果已经超过32位的数了,已经溢出了,所以这里得先转化为64位的

#21


16楼说的应该是对的,昨天早上我突然想到会不会是编译器对常量表达式默认的存储有问题,所以我把1000000000改为1000000000ul之后一切正常,这和你写的那个强制转化为(unsigned long)应该是一致的,不过之前我看过一本书,上面说过编译器会自动选择可以存储常量值大小的最低数据类型,所以当时出现了疑惑 ^_^

#22


14楼的 应该编译器是32位的,所以 long类型是32位

#23



对,我认为也应该是32位的

#24


6789ull + 8ull * 1000000000ull
把这些数字指明为unsigned long long看看。windows用6789ui64

#25


引用 24 楼 luciferisnotsatan 的回复:
6789ull + 8ull * 1000000000ull
把这些数字指明为unsigned long long看看。windows用6789ui64

32为下测试,输出正常

unsigned long long num = 6789ull + 8ull * 1000000000ull;
cout<<num;

6789这种数字,编译器默认应该是按int来解析的。不加后缀,整个计算过程都是按int来做,溢出了。然后才把那个错误值赋给 num。

#26


luciferisnotsatan正解
+法操作,使得6789进行隐士转换
显示转换

p.s 这个问题项目开发中比较常见,不同类型的操作,记得进行显示转换

#27


VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编并单步执行一遍不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编并单步执行。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”

提醒:
“学习用汇编语言写程序”

“VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编并单步执行一遍。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编并单步执行。)
想要从本质上理解C指针,必须学习C和汇编的对应关系。”
不是一回事!

C:\Program Files\Microsoft Visual Studio 8\VC\crt\src\limits.h
/***
*limits.h - implementation dependent values
*
*       Copyright (c) Microsoft Corporation.  All rights reserved.
*
*Purpose:
*       Contains defines for a number of implementation dependent values
*       which are commonly used in C programs.
*       [ANSI]
*
*       [Public]
*
****/

#if _MSC_VER > 1000
#pragma once
#endif  /* _MSC_VER > 1000 */

#include <crtdefs.h>

#ifndef _INC_LIMITS
#define _INC_LIMITS

#ifndef _CRTBLD
/* This version of the header files is NOT for user programs.
 * It is intended for use when building the C runtimes ONLY.
 * The version intended for public use will not have this message.
 */
#error ERROR: Use of C runtime library internal header file.
#endif  /* _CRTBLD */

#define CHAR_BIT      8         /* number of bits in a char */
#define SCHAR_MIN   (-128)      /* minimum signed char value */
#define SCHAR_MAX     127       /* maximum signed char value */
#define UCHAR_MAX     0xff      /* maximum unsigned char value */

#ifndef _CHAR_UNSIGNED
#define CHAR_MIN    SCHAR_MIN   /* mimimum char value */
#define CHAR_MAX    SCHAR_MAX   /* maximum char value */
#else  /* _CHAR_UNSIGNED */
#define CHAR_MIN      0
#define CHAR_MAX    UCHAR_MAX
#endif  /* _CHAR_UNSIGNED */

#define MB_LEN_MAX    5             /* max. # bytes in multibyte char */
#define SHRT_MIN    (-32768)        /* minimum (signed) short value */
#define SHRT_MAX      32767         /* maximum (signed) short value */
#define USHRT_MAX     0xffff        /* maximum unsigned short value */
#define INT_MIN     (-2147483647 - 1) /* minimum (signed) int value */
#define INT_MAX       2147483647    /* maximum (signed) int value */
#define UINT_MAX      0xffffffff    /* maximum unsigned int value */
#define LONG_MIN    (-2147483647L - 1) /* minimum (signed) long value */
#define LONG_MAX      2147483647L   /* maximum (signed) long value */
#define ULONG_MAX     0xffffffffUL  /* maximum unsigned long value */
#define LLONG_MAX     9223372036854775807i64       /* maximum signed long long int value */
#define LLONG_MIN   (-9223372036854775807i64 - 1)  /* minimum signed long long int value */
#define ULLONG_MAX    0xffffffffffffffffui64       /* maximum unsigned long long int value */

#if _INTEGRAL_MAX_BITS >= 8
#define _I8_MIN     (-127i8 - 1)    /* minimum signed 8 bit value */
#define _I8_MAX       127i8         /* maximum signed 8 bit value */
#define _UI8_MAX      0xffui8       /* maximum unsigned 8 bit value */
#endif  /* _INTEGRAL_MAX_BITS >= 8 */

#if _INTEGRAL_MAX_BITS >= 16
#define _I16_MIN    (-32767i16 - 1) /* minimum signed 16 bit value */
#define _I16_MAX      32767i16      /* maximum signed 16 bit value */
#define _UI16_MAX     0xffffui16    /* maximum unsigned 16 bit value */
#endif  /* _INTEGRAL_MAX_BITS >= 16 */

#if _INTEGRAL_MAX_BITS >= 32
#define _I32_MIN    (-2147483647i32 - 1) /* minimum signed 32 bit value */
#define _I32_MAX      2147483647i32 /* maximum signed 32 bit value */
#define _UI32_MAX     0xffffffffui32 /* maximum unsigned 32 bit value */
#endif  /* _INTEGRAL_MAX_BITS >= 32 */

#if _INTEGRAL_MAX_BITS >= 64
/* minimum signed 64 bit value */
#define _I64_MIN    (-9223372036854775807i64 - 1)
/* maximum signed 64 bit value */
#define _I64_MAX      9223372036854775807i64
/* maximum unsigned 64 bit value */
#define _UI64_MAX     0xffffffffffffffffui64
#endif  /* _INTEGRAL_MAX_BITS >= 64 */

#if _INTEGRAL_MAX_BITS >= 128
/* minimum signed 128 bit value */
#define _I128_MIN   (-170141183460469231731687303715884105727i128 - 1)
/* maximum signed 128 bit value */
#define _I128_MAX     170141183460469231731687303715884105727i128
/* maximum unsigned 128 bit value */
#define _UI128_MAX    0xffffffffffffffffffffffffffffffffui128
#endif  /* _INTEGRAL_MAX_BITS >= 128 */

#ifndef SIZE_MAX
#ifdef _WIN64
#define SIZE_MAX _UI64_MAX
#else  /* _WIN64 */
#define SIZE_MAX UINT_MAX
#endif  /* _WIN64 */
#endif  /* SIZE_MAX */

#if __STDC_WANT_SECURE_LIB__
/* While waiting to the C standard committee to finalize the decision on RSIZE_MAX and rsize_t,
 * we define RSIZE_MAX as SIZE_MAX
 */
#ifndef RSIZE_MAX
#define RSIZE_MAX SIZE_MAX
#endif  /* RSIZE_MAX */
#endif  /* __STDC_WANT_SECURE_LIB__ */


#endif  /* _INC_LIMITS */

#28


引用 19 楼 fengqiao1999 的回复:
理论上max = 2^64 - 1
num为什么会溢出,你可以检查下sizeof(unsigned long)为几字节。

我的机器和编译器都是64位的,sizeof(unsigned long)大小为8,上面问题,我认为是常量的存储问题

#29


谢谢各位,明白了错误所在了O(∩_∩)O哈哈~

#1


不要沉了,看到的给点思路,谢谢啊

#2


关注一下,32位机没法验证。

#3


32位机也可以验证的,得到的也不是预想的80多亿,也是溢出值

#4


蛮诡异哦,你看下汇编代码看看。

#5


看到汇编就头大 我去瞅瞅

#6


g++产生的汇编和以前学的X86汇编相差太大了,还是请高手指点

#7


大家不会都忙着过端午节吧?帮忙看一下啊,我都快欲哭无泪了……

#8


说说我的想法吧
我给你举个例子吧。(我的编译器长整形是占四个字节)
按照你的编译器无符号长整形是占8个字节。
unsigned long max = (unsigned long) (-1);//此处(-1)在内存是存的是补码  全部是1(总共64个1)
                                         //在转化成无符号长整数时。那么就应该是2^64-1
  cout<<max<<endl;//理论上应该输出为2的64次方再减一

楼主不知你的是多少???       
    

#9


恩,对,我上面描述有点小错误,是2的64次方-1,照理说这样的变量被赋上10亿不应该溢出的,但是却偏偏溢出了,g++编译时还有警告,说溢出……

#10


围观中。我试试也溢出了。期待大牛的出现。

#11


这个在32位机器上也是可以验证的,linux下的话用unsigned long long,windows下用unsigned uint_64 ,结果都会溢出,有人遇到过这样的问题吗?我实际工程中出现了这种情况,百思不得其解……

#12


此时如果再定义一个同样的变量,直接赋值,就像这样:
unsigned long numTemp = 8000006789;
cout<<numTemp<<endl;//此时输出正常,就是80多亿,这是神马情况?
看了一下两者的汇编代码,相差挺大的,不过不清楚,为什么会不一样的结果,因为对AT&T汇编不熟悉……

#13


引用楼主 wangluoqingfeng 的回复:
代码如下:
#include <iostream>
int main()
{
  using namespace std;
  unsigned long max = (unsigned long) (-1);
  cout<<max<<endl;//输出为2的64次方
  unsigned long num = 6789 + 8 * 1000000000;//80多亿
  cou……

在我的电脑上unsigned long只有32位
我认为
  //8 * 1000000000已经越界了
  long long 是64

#14


我的是64位机……,上面我说了,32位机 linux下你改成unsigned long long,windows下 你改成uint_64,上面的情况可以复现的

#15


引用 14 楼 wangluoqingfeng 的回复:
我的是64位机……,上面我说了,32位机 linux下你改成unsigned long long,windows下 你改成uint_64,上面的情况可以复现的


我也是64位机子,但unsigned long就只有32位,unsigned long long 是64位的

我也有点糊涂,直接赋值(没有运算时就是对的) 如:unsigned long long num=80456485686;
但unsigned long long num = 6789 + 8 * 1000000000;还是出现错了,会出现很大的数
18446744073709551615
18446744073119623569
请按任意键继续. . .

#16


编译器默认按32位分析6789 + 8 * 1000000000,因此警告溢出。我在VC下用以下形式,编译和运行结果都正常:

#include <stdio.h>
int main()
{
  unsigned __int64 max = (unsigned __int64) (-1);
  printf("%I64u",max);
  //unsigned __int64  num = 6789 + 8 * 1000000000;//warning C4307: '*' : integral constant overflow
  unsigned __int64  num = 6789 + 8 * (unsigned __int64)1000000000;

  printf("%I64u",num);
  return 0;
}

#17


引用 16 楼 logiciel 的回复:
编译器默认按32位分析6789 + 8 * 1000000000,因此警告溢出。我在VC下用以下形式,编译和运行结果都正常:


C/C++ code
#include <stdio.h>
int main()
{
  unsigned __int64 max = (unsigned __int64) (-1);
  printf("%I64u",max);
  //unsign……


我之前也是想这么认为的,运算默认是按32位来运算了,

unsigned long long num = 6789 + 8 * 1000000000;
会输出如下结果,我知道我错了,不是按32位来运算的
18446744073119623569

#18


哦,确实是按32位来计算了,我刚又验证了下

#19


理论上max = 2^64 - 1
num为什么会溢出,你可以检查下sizeof(unsigned long)为几字节。

#20


引用 19 楼 fengqiao1999 的回复:
理论上max = 2^64 - 1
num为什么会溢出,你可以检查下sizeof(unsigned long)为几字节。


运算的时候,运算数会转为32位的数进行运算,这是8 * 1000000000的结果已经超过32位的数了,已经溢出了,所以这里得先转化为64位的

#21


16楼说的应该是对的,昨天早上我突然想到会不会是编译器对常量表达式默认的存储有问题,所以我把1000000000改为1000000000ul之后一切正常,这和你写的那个强制转化为(unsigned long)应该是一致的,不过之前我看过一本书,上面说过编译器会自动选择可以存储常量值大小的最低数据类型,所以当时出现了疑惑 ^_^

#22


14楼的 应该编译器是32位的,所以 long类型是32位

#23



对,我认为也应该是32位的

#24


6789ull + 8ull * 1000000000ull
把这些数字指明为unsigned long long看看。windows用6789ui64

#25


引用 24 楼 luciferisnotsatan 的回复:
6789ull + 8ull * 1000000000ull
把这些数字指明为unsigned long long看看。windows用6789ui64

32为下测试,输出正常

unsigned long long num = 6789ull + 8ull * 1000000000ull;
cout<<num;

6789这种数字,编译器默认应该是按int来解析的。不加后缀,整个计算过程都是按int来做,溢出了。然后才把那个错误值赋给 num。

#26


luciferisnotsatan正解
+法操作,使得6789进行隐士转换
显示转换

p.s 这个问题项目开发中比较常见,不同类型的操作,记得进行显示转换

#27


VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编并单步执行一遍不就啥都明白了吗。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编并单步执行。)
想要从本质上理解C指针,必须学习汇编以及C和汇编的对应关系。
从汇编的角度理解和学习C语言的指针,原本看似复杂的东西就会变得非常简单!
指针即地址。“地址又是啥?”“只能从汇编语言和计算机组成原理的角度去解释了。”

提醒:
“学习用汇编语言写程序”

“VC调试时按Alt+8,TC或BC用TD调试,打开汇编窗口看每句C对应的汇编并单步执行一遍。
(Linux或Unix下应该也可以在用GDB调试时,看每句C对应的汇编并单步执行。)
想要从本质上理解C指针,必须学习C和汇编的对应关系。”
不是一回事!

C:\Program Files\Microsoft Visual Studio 8\VC\crt\src\limits.h
/***
*limits.h - implementation dependent values
*
*       Copyright (c) Microsoft Corporation.  All rights reserved.
*
*Purpose:
*       Contains defines for a number of implementation dependent values
*       which are commonly used in C programs.
*       [ANSI]
*
*       [Public]
*
****/

#if _MSC_VER > 1000
#pragma once
#endif  /* _MSC_VER > 1000 */

#include <crtdefs.h>

#ifndef _INC_LIMITS
#define _INC_LIMITS

#ifndef _CRTBLD
/* This version of the header files is NOT for user programs.
 * It is intended for use when building the C runtimes ONLY.
 * The version intended for public use will not have this message.
 */
#error ERROR: Use of C runtime library internal header file.
#endif  /* _CRTBLD */

#define CHAR_BIT      8         /* number of bits in a char */
#define SCHAR_MIN   (-128)      /* minimum signed char value */
#define SCHAR_MAX     127       /* maximum signed char value */
#define UCHAR_MAX     0xff      /* maximum unsigned char value */

#ifndef _CHAR_UNSIGNED
#define CHAR_MIN    SCHAR_MIN   /* mimimum char value */
#define CHAR_MAX    SCHAR_MAX   /* maximum char value */
#else  /* _CHAR_UNSIGNED */
#define CHAR_MIN      0
#define CHAR_MAX    UCHAR_MAX
#endif  /* _CHAR_UNSIGNED */

#define MB_LEN_MAX    5             /* max. # bytes in multibyte char */
#define SHRT_MIN    (-32768)        /* minimum (signed) short value */
#define SHRT_MAX      32767         /* maximum (signed) short value */
#define USHRT_MAX     0xffff        /* maximum unsigned short value */
#define INT_MIN     (-2147483647 - 1) /* minimum (signed) int value */
#define INT_MAX       2147483647    /* maximum (signed) int value */
#define UINT_MAX      0xffffffff    /* maximum unsigned int value */
#define LONG_MIN    (-2147483647L - 1) /* minimum (signed) long value */
#define LONG_MAX      2147483647L   /* maximum (signed) long value */
#define ULONG_MAX     0xffffffffUL  /* maximum unsigned long value */
#define LLONG_MAX     9223372036854775807i64       /* maximum signed long long int value */
#define LLONG_MIN   (-9223372036854775807i64 - 1)  /* minimum signed long long int value */
#define ULLONG_MAX    0xffffffffffffffffui64       /* maximum unsigned long long int value */

#if _INTEGRAL_MAX_BITS >= 8
#define _I8_MIN     (-127i8 - 1)    /* minimum signed 8 bit value */
#define _I8_MAX       127i8         /* maximum signed 8 bit value */
#define _UI8_MAX      0xffui8       /* maximum unsigned 8 bit value */
#endif  /* _INTEGRAL_MAX_BITS >= 8 */

#if _INTEGRAL_MAX_BITS >= 16
#define _I16_MIN    (-32767i16 - 1) /* minimum signed 16 bit value */
#define _I16_MAX      32767i16      /* maximum signed 16 bit value */
#define _UI16_MAX     0xffffui16    /* maximum unsigned 16 bit value */
#endif  /* _INTEGRAL_MAX_BITS >= 16 */

#if _INTEGRAL_MAX_BITS >= 32
#define _I32_MIN    (-2147483647i32 - 1) /* minimum signed 32 bit value */
#define _I32_MAX      2147483647i32 /* maximum signed 32 bit value */
#define _UI32_MAX     0xffffffffui32 /* maximum unsigned 32 bit value */
#endif  /* _INTEGRAL_MAX_BITS >= 32 */

#if _INTEGRAL_MAX_BITS >= 64
/* minimum signed 64 bit value */
#define _I64_MIN    (-9223372036854775807i64 - 1)
/* maximum signed 64 bit value */
#define _I64_MAX      9223372036854775807i64
/* maximum unsigned 64 bit value */
#define _UI64_MAX     0xffffffffffffffffui64
#endif  /* _INTEGRAL_MAX_BITS >= 64 */

#if _INTEGRAL_MAX_BITS >= 128
/* minimum signed 128 bit value */
#define _I128_MIN   (-170141183460469231731687303715884105727i128 - 1)
/* maximum signed 128 bit value */
#define _I128_MAX     170141183460469231731687303715884105727i128
/* maximum unsigned 128 bit value */
#define _UI128_MAX    0xffffffffffffffffffffffffffffffffui128
#endif  /* _INTEGRAL_MAX_BITS >= 128 */

#ifndef SIZE_MAX
#ifdef _WIN64
#define SIZE_MAX _UI64_MAX
#else  /* _WIN64 */
#define SIZE_MAX UINT_MAX
#endif  /* _WIN64 */
#endif  /* SIZE_MAX */

#if __STDC_WANT_SECURE_LIB__
/* While waiting to the C standard committee to finalize the decision on RSIZE_MAX and rsize_t,
 * we define RSIZE_MAX as SIZE_MAX
 */
#ifndef RSIZE_MAX
#define RSIZE_MAX SIZE_MAX
#endif  /* RSIZE_MAX */
#endif  /* __STDC_WANT_SECURE_LIB__ */


#endif  /* _INC_LIMITS */

#28


引用 19 楼 fengqiao1999 的回复:
理论上max = 2^64 - 1
num为什么会溢出,你可以检查下sizeof(unsigned long)为几字节。

我的机器和编译器都是64位的,sizeof(unsigned long)大小为8,上面问题,我认为是常量的存储问题

#29


谢谢各位,明白了错误所在了O(∩_∩)O哈哈~