C++中的long long与__int64
作者:Coder_LT 发布时间:2022-03-06 01:55:05
1、long long 和 __int64
在C++ Primer
当中提到的64位的int只有long long
,但是在实际各种各样的C++编译器当中,64位的int一直有两种标准。一种是long long
,还有一种是__int64
,非主流的VC甚至还支持_int64。
对于一般的C++开发者来说,其实这个问题不那么要紧,因为在实际开发当中,绝大多数情况使用32位的int就足够应付了。很少会出现超过int
范围的情况,但是对于算法玩家来说,这是一个必须考量的问题。因为很多题目会故意把范围弄得很大,考察选手对于数据范围的敏感。
关于long long
和__int64
,我们有非常多的问题要讨论,我们一个一个来说。
2、历史遗留问题
首先是聊聊这个问题的背景,为什么会有两种标准呢?这并不是C++的标准不严谨,或者是各大编译器乱来,背后是有一个历史遗留问题的。
long long
最早是C99标准引进的,然而VC6.0推出于1998年,在C99标准之前。所以当时微软就自己搞出来一个变量叫做__int64
来表示64位整数。很多同学使用的第一个C++的编译器就是VC6.0,所以记得在VC6.0当中要使用__int64
而非long long。
既然VC6.0搞出了__int64,那么微软后续的C++版本显然就必须要兼容它。所以在win系统当中,这个__int64
的变量类型就一直沿用了下来。当然,由于C++标准的更新,当然最新的visual studio
已经支持long long
了。
GCC并不是基于windows
系统的,自然支持long long
。win平台下的一些其他IDE如dev C++
,CodeBlocks
等也支持long long
,因为它们为了和微软的系统兼容,所以也支持__int64
。所以一个比较简单的区分方法是,判断编译器运行的操作系统是否是windows,如果是windows
使用__int64
,否则使用long long
。
3、cin、cout和scanf、printf的选择问题
这个问题对于C++开发工程师来说同样不是个问题,没有任何选择的必要,无脑用cin
、cout
就完事了。但对于算法竞赛玩家来说,这依然是一个要考虑的问题。
因为在算法竞赛当中,尤其是当数据量很大的时候,读入和输出占据的时间是非常可观的。看起来只是cin cout
和scanf
和printf
的差别,但是两者的性能差异非常大。
我曾经做过实验,同样的数据,使用scanf
和printf
的效率大约是cin
、cout
的十倍以上。在小数据量的时候当然没有差别,但数据量很大的时候影响非常大。很有可能导致同样的题目,同样的算法,别人通过了,但是我们却超时了的情况。
关于性能差异的原因,主要有两种解释。一种解释是说cin
为了与scanf
混用,而不用担心指针混乱,加上了绑定,总是会与stdin
保持同步。正是这一步操作消耗了大量的时间。同理,cout
也会有类似的问题。第二种解释是cout在输出之前会把要输出的内容先存入缓存区,中间多了一个步骤,也会带来性能的降低。
关于cin与stdin同步带来的开销,我们是有办法解决的,只需要在加上这一行代码:
std::ios::sync_with_stdio(false);
这行代码的意思是取消cin
、cout
与stdin
、stdout
的指针同步,会使得cin
、cout
的性能大大提升,达到和scanf
、printf
相差无几的程度。当然,更好的方法是使用scanf
、printf
代替。
而要使用scanf
和printf
又有一个问题,它们是C语言的标准输入输出方式,需要提供标识符来代表变量的类型,那么问题来了long long
和__int64
的标识符是什么呢?
这个其实一查就知道了,long long
的标识符是lld,所以我们使用scanf读入一个long long类型的数写成:
long long a;
scanf("%lld", &a);
__int64的标识符是I64d,注意这里是大写的i,不是l。
__int64 a;
scanf("%I64d", &a);
但是这里面有一个很大的坑点,前面说了,目前在windows
平台的编译器已经兼容了long long
类型。但是即便如此,在2013年之前的版本里,我们输出的时候还是要使用%I64d,这是因为微软提供的msvcrt.dll库只支持%I64d的方式。相当于从底层上断绝了使用%lld输出的可能。2013年微软修复了这个问题,添加了对 %lld 的支持。
所以比较简单的区分方法就是看操作系统,如果是windows
系统,那么一律使用__int64准没错。如果是linux或者是Mac系统,那么统一使用long long
。
我在网上找到了大神做的总结表,也可以直接参考下表:
变量定义 | 输出方式 | gcc(mingw32) | g++(mingw32) | gcc(linux i386) | g++(linux i386) | MicrosoftVisual C++ 6.0 |
---|---|---|---|---|---|---|
long long | “%lld” | 错误 | 错误 | 正确 | 正确 | 无法编译 |
long long | “%I64d” | 正确 | 正确 | 错误 | 错误 | 无法编译 |
__int64 | “lld” | 错误 | 错误 | 无法编译 | 无法编译 | 错误 |
__int64 | “%I64d” | 正确 | 正确 | 无法编译 | 无法编译 | 正确 |
long long | cout | 非C++ | 正确 | 非C++ | 正确 | 无法编译 |
__int64 | cout | 非C++ | 正确 | 非C++ | 无法编译 | 无法编译 |
long long | printint64() | 正确 | 正确 | 正确 | 正确 | 无法编译 |
注:文章转自微信公众号:Coder梁(ID:Coder_LT)


猜你喜欢
- 概述:堆排序是利用构建“堆”的方法确定具有最大值的数据元素,并把该元素与最后位置上的元素交换。可将任意一个由n个数据元素构成的序列按照(a1
- EasyDL图像分割介绍创建应用1.进入百度AI开放平台打开控制台:2.在左上角打开产品服务列表,找到EasyDL零门槛AI开放平台:3.打
- Java的接口和抽象类深入理解对于面向对象编程来说,抽象是它的一大特征之一。在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类。
- 成功本文通过java语言实现ECC+AES混合加密。ECC加密算法具有密钥分配与管理简单,安全强度高等优点,AES的加密算法具有速度快,强度
- 用AndroidStudio编写高级计算器带三角函数对数运算功能界面效果图:layout布局 activity_jisuanqi.xml代码
- 这篇文章主要介绍了Spring Bean初始化及销毁多种实现方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
- 之前看过一句话,说的特别好。有人问阅读源码有什么用?学习别人实现某个功能的设计思路,提高自己的编程水平。是的,大家都实现一个功能,不同的人有
- 当我们需要制作动态炫酷科技感很强的UI时,美术一般会给我们提供一些序列图,这时候我们只需在程序里实现序列动画。一.动画机unity自带的帧动
- 这篇文章主要介绍了SpringBoot 使用Mybatis分页插件实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参
- 本文实例为大家分享了unity实现贪吃蛇游戏的具体代码,供大家参考,具体内容如下首先创建一个头部,编写脚本利用WASD控制头部的移动。Vec
- 详解Kotlin:forEach也能break和continue这样的问题。也就是说,他们想用forEach而不是for循环,因为这很fp,
- SpringBoot v2.2以上重复读取Request Body内容一、需求项目有两个场景会用到从Request的Body中读取内容。打印
- Java(和其他语言)通过内部类支持嵌套类。要使其正常工作,需要编译器执行一些技巧。这是一个例子:public class Outer {
- 下载UEditorhttps://ueditor.baidu.com/website/download.html下载完整源码和JSP版本Sp
- 直接上代码新建DecimalInputTextWatcher类继承TextWatcher (代码可直接复制使用) import androi
- 本文实例为大家分享了java读取excel文件的具体代码,供大家参考,具体内容如下方式一:借用package com.ij34.util;/
- 基本要点1、Lombok作用:在我们的实体类中,我们再也不需要声明get、set、有参无参等方法,统统可以通过Lombok注解来实现同样的功
- 一、Java类的加载顺序引用1个网上的经典例子,并做稍许改动,以便大家更好地理解。public class Animal {
- 前言本文主要给大家介绍了关于Spring Boot集成之异步调用Async的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细
- 将int数组转化为Integer数组这里使用java8的stream来进行转化,详细步骤如下所示://初始化int数组int[] nums