cpp11~17 新基础类型--long long
时间: 03月23日
好的, 今天我们来分享一下long long这个类型, 还是比较有意思的.
对于 long long, c 语言在 c99(1999 年左右)
加入了标准, 而 cpp 是在 cpp11(大约 20011 年)
才加入标准.
long long 入 cpp 的小故事: long long这个类型早在1995年6月之前就由罗兰·哈丁格(Roland Hartinger)提出申请加入C++标准。但是当时的C++标准委员会以C语言中不存在这个基本类型为由,拒绝将这个类型加入C++中。而就在C++98标准出台的一年后,C99标准就添加了long long这个类型,并且流行的编译器也纷纷支持了该类型,这也就是我们很早就接触到long long的原因。在此之后C++标准委员会在C++11中才有计划将整型long long加入标准中。
C++标准中, long long 是一个至少为 64 位的整数类型.
这个"至少"写的就特别离谱, 在大部分编译器当中(至少在我用过的 VS2022 和 gcc 环境当中, long long
是 64 位的.
这个"至少"离谱在, 他没标准卡的特别严格, 导致可能会存在有些编译器会出现 64+位的 long long
也有可能.
C++标准中, long long 是一个有符号的类型.
实际上, long long = long long int = signed long long int. 同时, unsigned long long = unsigned long long int.
C++标准规定, long long 类型的字面量是 LL
和 ULL
我测试下来, 好像小写也是可以的, 不过小写有些字体会造成 两个 l(小写字母 l)
看成两个 '1'(读作"yi")
.
可以写作: long long x = 10LL;
不过因为都属于内置类型整形家族嘛, 所以说也是支持隐式类型转换的.
注意: 字面量后缀在运算时往往具有意义. 下面举一个典型的例子来说:
long long x1 = 65536 << 16.
std::cout << "x1 = " << x1 << std::endl; // 0
long long x2 = 65536LL << 16;
std::cout << "x2 = << x2 << std::endl; // 4294967296
之所以出现上面两种情况, 是因为计算机是先默认对于数字按照 int 类型进行处理和计算的, 但是我们第二种写法通过提前给他带一个后缀的方式, 计算机就可以直接按照 long long 的方式来对我们的程序进行计算了.
不过有一些编译器会提示(比如第一种写法, 编译器会警告两边类型不一致!), 而有一些编译器就不会报警告了, 编译器行为是由编译器厂商所决定的.
long long
类型也可以用于枚举类型和位域(联合体).
enum longlong_enum : long long{
x1 = 1,
x2,
x3
};
struct longlong_union{
long long x1 : 8;
long long x2 : 16;
long long x3 : 32;
};
long long 类型在头文件中范围有所确定和定义: 建议用类模板而非直接用宏.
#define LLONG_MAX 9223372036854775807LL // long long的最大值
#define LLONG_MIN (-9223372036854775807LL - 1) // long long的最小值
#define ULLONG_MAX 0xffffffffffffffffULL // unsigned long long的最大值
不过宏这个玩意在编译器看来是直接进行替换的, 因此是相当不安全, 不过倒是很方便(对于编译器来说). 因此 CPP 标准对标准库头文件做了扩展, 弄了一个模板类出来, 在这个模板类当中, 特化 long long 和 unsigned long long 版本, numeric_limits
类模板.
#include <iostream>
#include <limits>
#include <cstdio>
int main(int argc, char *argv[])
{
// 使用宏方法
std::cout << "LLONG_MAX = " << LLONG_MAX << std::endl;
std::cout << "LLONG_MIN = " << LLONG_MIN << std::endl;
std::cout << "ULLONG_MAX = " << ULLONG_MAX << std::endl;
// 使用类模板方法
std::cout << "std::numeric_limits<long long>::max() = "
<< std::numeric_limits<long long>::max() << std::endl;
std::cout << "std::numeric_limits<long long>::min() = "
<< std::numeric_limits<long long>::min() << std::endl;
std::cout << "std::numeric_limits<unsigned long long>::max() = "
<< std::numeric_limits<unsigned long long>::max() << std::endl;
// 使用printf打印输出
std::printf("LLONG_MAX = %lld\n", LLONG_MAX);
std::printf("LLONG_MIN = %lld\n", LLONG_MIN);
std::printf("ULLONG_MAX = %llu\n", ULLONG_MAX);
}
LLONG_MAX = 9223372036854775807
LLONG_MIN = -9223372036854775808
ULLONG_MAX = 18446744073709551615
std::numeric_limits<long long>::max() = 9223372036854775807
std::numeric_limits<long long>::min() = -9223372036854775808
std::numeric_limits<unsigned long long>::max() = 18446744073709551615
LLONG_MAX = 9223372036854775807
LLONG_MIN = -9223372036854775808
ULLONG_MAX = 18446744073709551615
std::printf
也对 long long
打印进行了特别支持, 新推出了%lld
和%llu
来格式化有符号和无符号的 long long 整形打印.
不过 CPP 中的流插入流提取可以自动识别类型, 倒是也是一个不错的选择.