首页 > 编程笔记 > C语言笔记 阅读:700

C语言unsigned的用法(非常详细)

在 C语言中,unsigned 是一个关键字,用于修饰整数类型(short、int、long 和 long long)。

unsigned的核心作用是将原本可以表示正、负数的整数类型变为只能表示非负数,从而扩展正数的范围。

对于初学者来说,理解 unsigned 的用法和影响非常重要,因为它直接关系到数据的存储和计算行为。这篇文章将详细讲解 unsigned 的定义、使用方法、适用场景以及注意事项,帮助你全面掌握它。

什么是unsigned

unsigned 是 C语言中的类型修饰符,意为“无符号”。

默认情况下,C语言的整数类型(如 intshort 等)是有符号的(signed),可以表示正数、负数和零。而加上 unsigned 后,该类型只能表示非负数(零和正数),取值范围从 0 开始,最大值翻倍。简单来说,它通过牺牲负数范围,换取更大的正数范围。


例如,一个 4 字节的 int


这背后的原理是:计算机用固定位数(例如 32 位)存储数字,有符号类型用 1 位表示符号,其余表示数值;而无符号类型将所有位都用于数值,从而范围更大。

关于整数在内存中是如何存储的,感兴趣的读者可阅读《整数在内存中是如何存储的,为什么它堪称天才般的设计》一文。

unsigned的基本用法

unsigned 可以与所有整数类型搭配使用,包括 shortintlonglong long。语法很简单,直接在类型前添加 unsigned 关键字即可。

和 unsigned 相对的,C语言还提供了 signed 关键字,意为“有符号”。默认情况下,所有的整数类型都是有符号类型,当然也可以用 signed 关键字显式指明。

语法示例:

unsigned int a = 100;
unsigned long b = 1234567890UL;

定义无符号整数常量时,建议加后缀 U(或 ULULL),以明确其类型,避免编译器警告。


让我们通过一个简单程序看看它的效果:

#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 在特定场景下非常有用,以下是几个典型例子:

  1. 表示非负数:如计数器、数组索引、文件大小等,天然不需要负数。
  2. 位操作:无符号类型更适合位运算,因为没有符号位干扰。
  3. 扩展范围:需要表示大于有符号类型最大值的正数时。


位操作示例:

#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) 与有符号类型混合运算

unsignedsigned 类型混合运算时,会发生类型提升,通常提升为无符号类型,可能导致意外结果。例如:

#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 的用法有了全面认识,在实际编程中游刃有余!

相关文章