在 C++ 中,int
和 unsigned int
是最常用的整型类型,它们在语义、范围、计算行为上都有明显区别。以下是详细解释,并结合代码示例说明差异与注意事项。
一、int
和 unsigned int
的基本定义
类型 | 含义 | 数值范围(32位) |
---|---|---|
int | 有符号整型 | -2,147,483,648 ~ 2,147,483,647 |
unsigned int | 无符号整型(只表示正数) | 0 ~ 4,294,967,295 |
int
默认是有符号,等价于signed int
。unsigned int
不包含负数,只有 0 和正整数。
二、使用区别举例
示例1:基本赋值
int a = -10;
unsigned int b = 10;
std::cout << a << std::endl; // 输出 -10
std::cout << b << std::endl; // 输出 10
示例2:溢出行为
unsigned int u = 0;
u = u - 1;
std::cout << u << std::endl; // 输出 4294967295(因为 unsigned 不支持负数,结果变成了最大值)
- 这是无符号整数的环绕行为(Wrap around)。
三、常见错误用法
错误 1:int
与 unsigned int
混用时的比较问题
int a = -1;
unsigned int b = 1;
if (a < b)
std::cout << "a < b" << std::endl;
else
std::cout << "a >= b" << std::endl;
输出将是 a >= b
!因为:
a
被自动转换成unsigned int
,其值变成 很大很大(> 1)。
⚠️ 避免 int
与 unsigned int
混用比较!
四、循环中的典型陷阱
unsigned int n = 5;
for (int i = n - 1; i >= 0; --i) {
std::cout << i << std::endl;
}
这段代码会死循环(或产生意外行为),因为:
n - 1
是unsigned int
,结果是4u
;- 然后赋值给
int i
,没问题; - 但是当
i = 0
后,--i
变成-1
,条件i >= 0
不成立,退出循环; - 正确写法:
for (int i = static_cast<int>(n) - 1; i >= 0; --i)
或者完全使用 unsigned int
时要特别注意:
for (unsigned int i = n; i-- > 0;) {
std::cout << i << std::endl;
}
五、类型转换和安全性建议
- 显式类型转换(
static_cast
)是安全做法:
unsigned int u = 1234;
int i = static_cast<int>(u);
- 避免隐式转换引发 bug(例如混用比较、赋值)。
六、实践代码总结(完整示例)
#include <iostream>
#include <limits>
int main() {
int a = -42;
unsigned int b = 42;
std::cout << "int a = " << a << std::endl;
std::cout << "unsigned int b = " << b << std::endl;
// 混合比较
if (a < b)
std::cout << "a < b" << std::endl;
else
std::cout << "a >= b (warning: signed/unsigned comparison)" << std::endl;
// 溢出
unsigned int c = 0;
c = c - 1;
std::cout << "unsigned underflow: " << c << std::endl;
// 安全循环
std::cout << "Countdown using unsigned int safely:" << std::endl;
for (unsigned int i = 5; i-- > 0;) {
std::cout << i << " ";
}
std::cout << std::endl;
return 0;
}
七、总结建议
建议 | 原因 |
---|---|
尽量统一使用 int 除非你明确需要无符号数 | 混合使用容易导致比较错误和溢出问题 |
避免 int 与 unsigned int 混合运算 | C++ 会隐式转换为 unsigned ,导致 bug |
对循环、比较操作,手动加 static_cast 明确类型 | 防止类型冲突或逻辑错误 |
使用 std::numeric_limits<T>::max() 来处理边界 | 避免硬编码极限值 |