~对int取反是对所有位(含符号位)按位取反,因int默认为补码表示,结果不等于数学负数或逻辑非,如x=1时~x为-2而非-1。

为什么 ~ 对 int 取反结果不是简单翻每个 0/1?
因为 int 在 C++ 中默认是有符号整数,用补码表示。直接写 ~x 是对所有位(包括符号位)取反,结果不等于数学意义上的“负 x”或“非 x”,而是补码体系下的按位翻转。
常见错误现象:int x = 1; std::cout 输出 <code>-2,而不是 0xFFFFFFFE 或预期的 “全 1 除最低位”。这是因为 1 的 32 位补码是 0x00000001,~ 后变成 0xFFFFFFFE,而该值在有符号 int 解释下就是 -2。
- 如果要得到无符号视角的翻转结果,显式转成
unsigned int再取反:~static_cast<unsigned int>(x)</unsigned> - 若目标是“求负数”(即
-x),别用~,它不等价于取负;正确做法是直接写-x或用0 - x - 注意:对
char、short等小整型做~会先整型提升(promoted)为int,再取反,结果位宽是int的,不是原类型的 —— 这常被忽略
~ 和 ! 完全不是一回事
! 是逻辑非,只关心值是否为 0;~ 是按位取反,逐 bit 翻转。两者类型、语义、结果都不同。
使用场景举例:判断标志位是否全清空,用 if ((flags & MASK) == 0),不是 if (!(flags & MASK))(虽然有时碰巧等效),更不是 if (~(flags & MASK))(这几乎总是错的)。
立即学习“C++免费学习笔记(深入)”;
-
!5→0,~5(假设 32 位)→-6 -
!0→1,~0→-1(有符号解释下)或UINT_MAX(无符号解释下) - 编译器不会警告你混用它们,但行为差异极大 —— 尤其在条件分支或位掩码计算中
用 ~ 构造掩码时怎么避免符号扩展陷阱?
想定义一个“低 4 位为 0,其余为 1”的掩码,容易写成 ~0xF。看起来没问题,但实际取决于上下文类型:0xF 是 int,~0xF 得到的是 0xFFFFFFF0(32 位),但如果代码跑在 64 位平台且你期望 0xFFFFFFFFFFFFFFF0,就可能出错。
- 安全写法:用无符号字面量,如
~0xFU(得unsigned int)、~0xFULL(得unsigned long long) - 更推荐显式宽度:用
std::numeric_limits<uint32_t>::max() ^ 0xF</uint32_t>或直接写0xFFFFFFF0U - 宏定义掩码时尤其要注意:#define MASK (~0xF) 是危险的,应改为 #define MASK (~0xFU)
GCC/Clang 下 ~ 遇到负数常量会怎样?
像 ~-1 这种写法是合法的,但结果依赖于字面量类型和平台。C++ 标准规定负数字面量(如 -1)本身不是“负的整数字面量”,而是 unary minus 作用于正数字面量,所以 ~-1 实际等价于 ~(0 - 1) → ~(-1)。
常见错误现象:在模板推导或 constexpr 上下文中,~-1 可能因类型不明确导致 SFINAE 失败或编译错误。
- 避免依赖隐式类型:写
~static_cast<int>(-1)</int>或~(-1i32)(C++23 整数字面量后缀)更清晰 - constexpr 函数里用
~时,确保操作数类型确定,否则可能触发未定义行为(比如对有符号溢出值取反) - Clang 警告
-Wsign-conversion会提示~导致的符号转换问题,建议打开
最麻烦的地方往往不在怎么写 ~,而在于你没意识到它操作的是整个存储位宽,且解释权完全交给后续怎么用那个结果 —— 类型一变,意义全改。










