C语言unsigned的用法(非常详细)
在 C语言中,unsigned 是一个关键字,用于修饰整数类型(short、int、long 和 long long)。
unsigned的核心作用是将原本可以表示正、负数的整数类型变为只能表示非负数,从而扩展正数的范围。
对于初学者来说,理解 unsigned 的用法和影响非常重要,因为它直接关系到数据的存储和计算行为。这篇文章将详细讲解 unsigned 的定义、使用方法、适用场景以及注意事项,帮助你全面掌握它。
什么是unsigned
unsigned 是 C语言中的类型修饰符,意为“无符号”。
默认情况下,C语言的整数类型(如 int、short 等)是有符号的(signed),可以表示正数、负数和零。而加上 unsigned 后,该类型只能表示非负数(零和正数),取值范围从 0 开始,最大值翻倍。简单来说,它通过牺牲负数范围,换取更大的正数范围。
例如,一个 4 字节的 int:
-
有符号(
signed int):-2,147,483,648 到 2,147,483,647 -
无符号(
unsigned int):0 到 4,294,967,295
这背后的原理是:计算机用固定位数(例如 32 位)存储数字,有符号类型用 1 位表示符号,其余表示数值;而无符号类型将所有位都用于数值,从而范围更大。
关于整数在内存中是如何存储的,感兴趣的读者可阅读《整数在内存中是如何存储的,为什么它堪称天才般的设计》一文。
unsigned的基本用法
unsigned 可以与所有整数类型搭配使用,包括 short、int、long 和 long long。语法很简单,直接在类型前添加 unsigned 关键字即可。
和 unsigned 相对的,C语言还提供了 signed 关键字,意为“有符号”。默认情况下,所有的整数类型都是有符号类型,当然也可以用 signed 关键字显式指明。
语法示例:
unsigned int a = 100; unsigned long b = 1234567890UL;
定义无符号整数常量时,建议加后缀 U(或 UL、ULL),以明确其类型,避免编译器警告。
让我们通过一个简单程序看看它的效果:
#include <stdio.h>
int main(void) {
unsigned int ui = 4000000000U;
int si = -100;
printf("Unsigned int: %u\n", ui);
printf("Signed int: %d\n", si);
return 0;
}
输出结果:
Unsigned int: 4000000000 Signed int: -100
在这里,unsigned int 能表示 40 亿,而普通 int 的最大值约为 21 亿,超出则溢出。
unsigned的取值范围
unsigned 修改后的取值范围取决于类型的大小。以下是常见类型的范围(假设标准字节大小):
| 类型 | 大小(字节) | 无符号范围 |
|---|---|---|
unsigned short |
2 | 0 到 65,535 (216-1) |
unsigned int |
4 | 0 到 4,294,967,295 (232-1) |
unsigned long |
4 或 8(平台相关) | 0 到 232-1 或 264-1 |
unsigned long long |
8 | 0 到 18,446,744,073,709,551,615 (264-1) |
你可以用 sizeof 检查具体大小,并通过头文件 <limits.h>获取范围常量(如 UINT_MAX)。
#include <stdio.h>
#include <limits.h>
int main(void) {
printf("Max unsigned int: %u\n", UINT_MAX);
printf("Max unsigned long: %lu\n", ULONG_MAX);
return 0;
}
输出结果(示例,依平台而异):
Max unsigned int: 4294967295 Max unsigned long: 4294967295
unsigned格式化输出
使用 printf 输出无符号整数时,需要选择正确的格式说明符,以匹配类型:
unsigned short: %hu unsigned int: %u unsigned long: %lu unsigned long long: %llu
如果格式不匹配(例如用 %d 输出 unsigned int),结果可能是错误的。
unsigned使用场景
unsigned 在特定场景下非常有用,以下是几个典型例子:
- 表示非负数:如计数器、数组索引、文件大小等,天然不需要负数。
- 位操作:无符号类型更适合位运算,因为没有符号位干扰。
- 扩展范围:需要表示大于有符号类型最大值的正数时。
位操作示例:
#include <stdio.h>
int main(void) {
unsigned int mask = 0xF0U; // 十六进制表示 11110000
unsigned int value = 0xAAU; // 10101010
printf("Result: %u\n", mask & value); // 按位与
return 0;
}
输出结果:
Result: 160 (0xA0,即 10100000)
unsigned注意事项
虽然 unsigned 很有用,但使用不当可能导致问题。以下是一些关键注意点:
1) 溢出行为
无符号整数溢出时会“回绕”到 0,而不是未定义行为。例如:
#include <stdio.h>
int main(void) {
unsigned int max = 4294967295U; // UINT_MAX
printf("Max: %u\n", max);
printf("Max + 1: %u\n", max + 1);
return 0;
}
输出结果:
Max: 4294967295 Max + 1: 0
这与有符号整数溢出(未定义行为)不同,但仍需小心处理。
2) 与有符号类型混合运算
当 unsigned 和 signed 类型混合运算时,会发生类型提升,通常提升为无符号类型,可能导致意外结果。例如:
#include <stdio.h>
int main(void) {
int si = -1;
unsigned int ui = 1U;
if (si < ui) {
printf("si < ui is true\n");
}
if (si > ui) {
printf("si > ui is true\n"); // 意外结果
}
return 0;
}
输出结果:
si > ui is true
原因:si 被提升为无符号整数,-1 变为 4294967295(假设 4 字节),大于 1。
解决方法:避免混合运算,或显式转换类型,如 (int)ui。
3) 不适用于负值
试图将负值赋给无符号类型会导致回绕。例如:
#include <stdio.h>
int main(void) {
unsigned int ui = -1;
printf("ui = %u\n", ui);
return 0;
}
输出结果:
ui = 4294967295
这里,-1 被解释为最大值,而不是负数。
总结
unsigned 关键字是 C语言中处理非负整数的强大工具,它通过改变整数的表示范围,适用于计数、位操作和大正数场景。
搞清楚unsigned的取值范围、输出格式和潜在陷阱,可以帮助你更安全、高效地使用它。希望这篇教程让你对 unsigned 的用法有了全面认识,在实际编程中游刃有余!
ICP备案:
公安联网备案: