-9223372036854775808为什么会溢出?

liuzhenpolestar 2019-05-14 11:43:15
c99中,long long int 的取值范围是 -9223372036854775808~-9223372036854775807。
那为什么编译时显示“[Warning] integer constant is so large that it is unsigned [enabled by default]”,而且输出的结果也是错的。
printf("%lld\n", -9223372036854775808ll); //输出的值是2293312

在https://zh.cppreference.com/w/c/language/integer_constant中指出了这个问题,但没说明为什么!请大家讨论!
...全文
1341 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
赵4老师 2019-05-15
  • 打赏
  • 举报
回复
常量也有类型!
liuzhenpolestar 2019-05-14
  • 打赏
  • 举报
回复
引用 4 楼 拥抱Linux 的回复:
你给的cppreference的整数常量的页面里,谈到了这一点啊。
引用
注意 没有负整数常量。如 -1 的表达式是将一元负运算符应用到常量所表示的值,可能会引起隐式类型转换。
页面上也给出了相应的正确的语句写法。还提到了:
引用
若整数常量过大从而无法符合后缀/底结合所允许的任何类型,且编译器支持扩展整数类型(譬如 __int128 ),则常量可能以扩展整数类型给出;否则程序为病式。
另外,在本地和在线编译器上试了一下,不同的编译器、不同的版本给出的Warning不尽相同。本地 gcc 5.4.0 给的是:

2.c: In function ‘main’:
2.c:7:37: warning: integer constant is so large that it is unsigned
  printf("format of %%lld, %lld\n", -9223372036854775808ll);
                                     ^
2.c:7:9: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 2 has type ‘__int128’ [-Wformat=]
  printf("format of %%lld, %lld\n", -9223372036854775808ll);
不过,结果还是期望的「 -9223372036854775808」,这个估计和具体的系统环境、编译器都有关系,不单单是c99而已。 ~
谢谢你!我用的编译器是dev c++自带的,版本较老了。tdm gcc4.8.1版本。
liuzhenpolestar 2019-05-14
  • 打赏
  • 举报
回复
引用 1 楼 636f6c696e 的回复:
linux下加入-std=c99编译选项不会有这告警,输出也是对的,你的编译环境是什么?
我也已经加过这个选项了
liuzhenpolestar 2019-05-14
  • 打赏
  • 举报
回复
引用 1 楼 636f6c696e 的回复:
linux下加入-std=c99编译选项不会有这告警,输出也是对的,你的编译环境是什么?
dev c++ gcc
拥抱Linux 2019-05-14
  • 打赏
  • 举报
回复
你给的cppreference的整数常量的页面里,谈到了这一点啊。
引用
注意
没有负整数常量。如 -1 的表达式是将一元负运算符应用到常量所表示的值,可能会引起隐式类型转换。

页面上也给出了相应的正确的语句写法。还提到了:
引用
若整数常量过大从而无法符合后缀/底结合所允许的任何类型,且编译器支持扩展整数类型(譬如 __int128 ),则常量可能以扩展整数类型给出;否则程序为病式。

另外,在本地和在线编译器上试了一下,不同的编译器、不同的版本给出的Warning不尽相同。本地 gcc 5.4.0 给的是:

2.c: In function ‘main’:
2.c:7:37: warning: integer constant is so large that it is unsigned
printf("format of %%lld, %lld\n", -9223372036854775808ll);
^
2.c:7:9: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 2 has type ‘__int128’ [-Wformat=]
printf("format of %%lld, %lld\n", -9223372036854775808ll);

不过,结果还是期望的「 -9223372036854775808」,这个估计和具体的系统环境、编译器都有关系,不单单是c99而已。
赵4老师 2019-05-14
  • 打赏
  • 举报
回复
单步printf语句对应的汇编代码几步后,就会来到printf对应的C源代码output.c处。
赵4老师 2019-05-14
  • 打赏
  • 举报
回复
理解讨论之前请先学会如何观察! 提醒:printf是开源的。 参考:Microsoft Visual Studio 10.0\VC\crt\src\output.c Visual C++ 2010 Express简体中文版http://pan.baidu.com/s/1bnwRVLt
636f6c696e 2019-05-14
  • 打赏
  • 举报
回复
linux下加入-std=c99编译选项不会有这告警,输出也是对的,你的编译环境是什么?
liuzhenpolestar 2019-05-14
  • 打赏
  • 举报
回复
谢谢大家。我总结一下。 输出-9223372036854775808的正确方式为: printf("%lld\n", -9223372036854775807ull - 1); // 组成有符号值 -9223372036854775808 的正确方式 或 printf("%lld\n", -9223372036854775808ull); 这样是把数值-2^63(或-2^63+1)转成了无符号长长整数,其值为2^63(或2^63+1),值为2^63+1时,减去1后,仍为2^63。而在输出时用%lld,因为在内存中2^63是以1000,0000,0000,此处省略48个0,0000存储的,所以正好是-2^63。这样也不会溢出还能正确的输出值。只是这个技巧让我感觉计算机里的东西“有点东拼西凑投机取巧的感觉”,透出一种无奈。唉没有完美的东西吧。 谢谢各位兄弟的回帖!对我有很大的帮助与启发。谢谢你们!!
liuzhenpolestar 2019-05-14
  • 打赏
  • 举报
回复
但是可以试想即使支持128位,也会有一个负数正好是MIN=-2^127-1。这个数依旧溢出啊
引用 9 楼 拥抱Linux 的回复:
[quote=引用 7 楼 liuzhenpolestar 的回复:] 谢谢你!我用的编译器是dev c++自带的,版本较老了。tdm gcc4.8.1版本。
试试根据你给的 cppreference 的 整数常量 的页面里给出的 正确的 语句,在你的 编译器里 再运行看看会是什么结果呢? ~[/quote] 它给出的运行结果是对的。我想明白了。这样是把数值-2^63转成了无符号长长整数,其值为2^63,而在输出时用%lld,因为在内存中它,是以1000,0000,0000,此处省略48个0,0000存储的,所以正好是-2^63。这样也不会溢出还能正确的输出值。只是这个技巧让我感觉计算机里的东西“有点东拼西凑投机取巧的感觉”。唉没有完美的东西吧。谢谢各位兄弟的回帖!对我有很大的帮助与启发。谢谢你们!!
拥抱Linux 2019-05-14
  • 打赏
  • 举报
回复
引用 7 楼 liuzhenpolestar 的回复:
谢谢你!我用的编译器是dev c++自带的,版本较老了。tdm gcc4.8.1版本。


试试根据你给的 cppreference 的 整数常量 的页面里给出的 正确的 语句,在你的 编译器里 再运行看看会是什么结果呢?
CaptainXue 2019-05-14
  • 打赏
  • 举报
回复
windows下我在dev-c++的编译环境中虽然出现了警告,但还是正确输出结果了的,这个应该和你的编译环境有关系!附上我的代码和截图:

#include<stdio.h>
#include<math.h>
#include<iostream>
using namespace std;
main(void ) {
long long a=-9223372036854775808;
printf("%lld\n", a);
}

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧