long long 和 int64_t 在绝大多数现代平台下等价,但语义与可移植性不同:前者是c++11标准类型,后者是定义的精确宽度别名;int64_t更适用于序列化等需严格64位的场景,long long更便携。

long long 和 int64_t 到底是不是一回事
不是完全等价,但绝大多数现代平台下它们底层都是 64 位有符号整数,行为一致。关键区别在于:前者是 C++ 语言标准定义的类型(C++11 起),后者是头文件 <cstdint></cstdint> 提供的精确宽度别名。
常见错误现象:int64_t 在某些嵌入式或老编译器(如旧版 MSVC)里可能未定义,而 long long 只要编译器支持 C++11 就一定可用;反过来,long long 在极少数平台(比如某些 DSP 编译器)可能被映射为 128 位,但这种情况在 x86/x64/ARM 主流环境几乎不存在。
- 用
long long更便携——只要你在写标准 C++11+ 代码 - 用
int64_t更明确——你真的需要“恰好 64 位”,比如序列化、网络协议、内存布局敏感场景 - 不要混用做 typedef 或模板推导,比如
using T = int64_t;然后传给期望long long的函数,可能因类型不完全相同导致重载失败或模板实例化歧义
printf / scanf 怎么安全输出 long long
long long 没有统一的格式说明符标准,不同平台差异明显,这是最容易崩的地方。
Windows 下(MSVC、MinGW)必须用 "%I64d",Linux/macOS(GCC/Clang)用 "%lld"。用错会直接导致输出乱码、崩溃或静默截断。
立即学习“C++免费学习笔记(深入)”;
- 跨平台项目优先用
std::cout ,它自动适配 <code>long long - 非要用
printf?查<cinttypes></cinttypes>:用PRIi64宏,配合int64_t—— 写成printf("%" PRId64, x); - 别试图自己宏判断平台来切格式串,
<cinttypes></cinttypes>已经帮你做了 -
scanf同理:%" SCNd64对应int64_t *,而不是&x直接塞long long *
和 int 混算时的隐式转换陷阱
看起来只是“小整数 + 大整数”,但实际会发生整型提升和符号扩展,结果可能出人意料。
典型错误现象:在 32 位系统上,int 是 32 位,long long 是 64 位。表达式 int a = -1; long long b = a 不会报错,但左移 32 位对 <code>int 是未定义行为(UB),编译器可能优化掉整条语句,或者给出意外值。
- 所有涉及位运算、移位、无符号/有符号混合的操作,先显式转成同类型再算,比如
static_cast<long long>(a) </long> - 比较时也一样:
if (x > y)中x是int、y是long long,x会被提升,但若x是负数且高位被补全,逻辑仍正确;可读性差,建议统一转成long long - 函数参数传递尤其危险:某个接口声明为
void f(int),你传long long x = 10000000000LL;,会静默截断——编译器只在开启-Wconversion时警告
constexpr 和模板推导里的宽度稳定性
模板元编程或 constexpr 计算中,你以为 long long 是稳定的,但它在不同编译器常量折叠阶段可能被当作不同底层类型处理,影响 std::is_same_v 或 decltype 结果。
使用场景:写一个通用的整数序列生成器,模板参数是数值类型,你希望 make_seq<int64_t></int64_t> 和 make_seq<long long></long> 触发同一份特化,但实际可能分叉。
- 坚持用
int64_t做模板参数或类型别名,它语义唯一、宽度固定 - 如果必须接受用户传
long long,在模板入口处统一转成int64_t:比如using T = std::common_type_t<u int64_t></u>或直接static_assert(std::is_same_v<:remove_cvref_t>, int64_t>)</:remove_cvref_t> -
constexpr函数返回类型尽量显式写int64_t,避免依赖编译器对字面量的默认推导(比如1LL在某些上下文可能被当long)
最麻烦的其实是调试——GDB 或 IDE 变量窗口里显示 long long 和 int64_t 有时名字不同,但值一样,容易误判类型问题。盯住内存布局和实际值,别信显示名。










