🦄个人主页:小米里的大麦-CSDN博客
🎏所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html
🎁代码托管:C语言: C语言方向(基础知识和应用) (gitee.com)
⚙️操作环境:Visual Studio 2022
目录
一、介绍
大家好!今天我想跟大家分享一些关于 C 语言整数类型及其数据范围的相关知识,特别是它们的位数和数值范围。这是编程中非常基础但又容易被忽视的部分,了解这些可以帮助我们更好地编写高效和可靠的代码。
二、整数类型表
在 C 语言中,整数类型是我们最常用的类型之一。它们包括了
char
,short
,int
,long
,long long
以及它们的无符号版本。每种类型都有其特点和用途,了解它们可以帮助我们在实际编程中做出更好的选择。
首先,让我们通过一张图片来快速了解各种整数类型的位数和数值范围:
- 注意:对于无符号类型,最小值始终为0,最大值是其位数所能表示的最大整数值。括号内的数值表示的是 C 语言标准的最小要求,实际的实现可能会根据编译器和目标平台有所不同。例如,在大多数现代系统中,
int
通常是 32 位,long
在 32 位系统上通常是 32 位,在 64 位系统上通常是 64 位。在表格中,我们使用了以下符号:
N/A
表示不适用,因为无符号类型没有负数的概念。≥
表示该类型至少需要具备的位数,实际的位数可能会更多。这个表格提供了关于 C 语言整数类型的详细信息,包括它们的位数和数值范围。请注意,虽然这些是最小要求,实际的实现可能会有所不同。例如,在大多数现代系统中:
int
通常是 32 位。long
在 32 位系统上通常是 32 位,在 64 位系统上通常是 64 位。long long
通常是 64 位。为了确保你的程序能够在不同的平台上正确地工作,建议使用标准定义的宏(如
<limits.h>
和<stdint.h>
中提供的)来获取类型的确切大小和范围。
当然,还有表格版(同上):
数据类型 | 位数 | 最小值(有符号) | 最大值(有符号) | 最小值(无符号) | 最大值(无符号) |
char | 8 | -128 | 127 | 不适用 | 255* |
unsigned char | 8 | 不适用 | 不适用 | 0 | 255 |
short | ≥16 | -32,768 | 32767 | 不适用 | 65335* |
unsigned short | ≥16 | 不适用 | 不适用 | 0 | 65535 |
int | ≥16 | -32,768 | 32767 | 不适用 | 65535* |
unsigned int | ≥16 | 不适用 | 不适用 | 0 | 65535 |
long (32位系统) | ≥32 | -2,147,483,648 | 2,147,483,647 | 不适用 | 4,294,967,295* |
unsigned long (32位) | ≥32 | 不适用 | 不适用 | 0 | 4,294,967,295 |
long (64位系统) | ≥32 | -9,223,372,036,854,775,808 | 9,223,372,036,854,775,807 | 不适用 | 18,446,744,073,709,551,615* |
unsigned long (64位) | ≥32 | 不适用 | 不适用 | 0 | 18,446,744,073,709,551,615 |
一定注意:对于无符号类型,最小值始终为0,最大值是其位数所能表示的最大整数值。括号内的数值表示的是 C 语言标准的最小要求,实际的实现可能会根据编译器和目标平台有所不同。
1.分析
char
和unsigned char
char
:通常为 8 位,可以存储从 -128 到 127 的值。它非常适合存储文本字符。unsigned char
:同样为 8 位,但只能存储从 0 到 255 的值。它适合存储不需要负数的情况,例如图像像素值。
short
和unsigned short
short
:至少 16 位,可以存储从 -32,768 到 32,767 的值。它适用于存储较小的整数。unsigned short
:同样至少 16 位,可以存储从 0 到 65,535 的值。它适合存储不需要负数的较小整数。
int
和unsigned int
int
:至少 16 位,但通常为 32 位,在大多数现代系统中。它可以存储从 -32,768 到 32,767 或者更大范围的值。unsigned int
:同样至少 16 位,但通常为 32 位,在大多数现代系统中。它可以存储从 0 到 65,535 或者更大范围的值。
long
和unsigned long
long
:至少 32 位,但在 32 位系统上通常是 32 位,在 64 位系统上通常是 64 位。它可以存储从 -2,147,483,648 到 2,147,483,647 或者更大范围的值。unsigned long
:同样至少 32 位,但在 32 位系统上通常是 32 位,在 64 位系统上通常是 64 位。它可以存储从 0 到 4,294,967,295 或者更大范围的值。
long long
和unsigned long long
long long
:至少 64 位,在大多数系统上也是 64 位。它可以存储从 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 的值。unsigned long long
:同样至少 64 位,在大多数系统上也是 64 位。它可以存储从 0 到 18,446,744,073,709,551,615 的值。
2.小结
了解这些类型的特点和限制对于编写高效的代码非常重要。记住,实际的位数可能会根据编译器和目标平台有所不同。为了确保程序的可移植性和可靠性,请考虑使用
<limits.h>
或<stdint.h>
中的宏来获取确切的类型大小和范围。
三、截断
上面,我们介绍了 C 语言中不同整数类型的位数和数值范围。现在,我们将深入了解一个重要的概念 —— 截断(Truncation),它发生在当我们试图将一个值存储到一个不能完全容纳它的数据类型中时。了解截断现象对于避免潜在的错误和提高代码质量至关重要。
1.什么是截断?
在 C 语言中,截断是指当一个较大的数值被赋给一个较小的数据类型时,超出该类型表示范围的部分被丢弃的过程。例如,如果我们试图将一个大于 255 的数值赋给一个
unsigned char
类型的变量,那么超出 8 位的部分将被截掉。
2.为什么需要截断?
截断主要是由于数据类型的位数限制。每种整数类型都有固定的位数,这决定了它可以表示的数值范围。当一个数值超过了该类型的最大表示能力时,就必须通过截断来适应存储限制。
示例
假设我们有一个
unsigned char
类型的变量a
,它只能存储从 0 到 255 的值。现在我们尝试将一个更大的值,比如说 300,赋给a
。由于unsigned char
只能存储 8 位,即最多 255,那么 300 的二进制表示为 100101100,但是unsigned char
只能存储最后 8 位,也就是 00101100,这相当于十进制中的 44。
3.截断的意义
了解截断现象的意义在于避免因类型不匹配而导致的意外行为。截断可能会导致数据丢失或产生未预期的结果。例如,如果一个计算结果需要精确到某个数值范围之外,但最终被存储到一个较小的数据类型中,那么可能会导致错误的输出。
实际应用
让我们通过一个简单的例子来说明这一点。假设我们有一个 unsigned char
类型的变量 c
和两个 unsigned char
类型的变量 a
和 b
,分别初始化为 200 和 100。
#include <stdio.h>
int main() {
unsigned char a = 200; // 二进制 11001000
unsigned char b = 100; // 二进制 01100100
unsigned char c = 0;
c = a + b; // 尝试将 300 存储到 c 中
printf("a + b = %d, c = %d\n", a + b, c);
return 0;
}
在这个例子中,
a + b
的结果是 300,但是在将 300 赋给c
时发生了截断。300 的二进制表示为 100101100,而c
只能存储 8 位,因此只保留了最后 8 位 00101100,这等于十进制中的 44。因此,输出将是:
a + b = 300, c = 44
4.如何避免截断?
为了避免截断导致的问题,你可以采取以下几种策略:
- 使用适当的数据类型:确保你选择的数据类型能够容纳你需要存储的数值范围。
- 类型转换:在赋值之前显式地转换类型,例如使用
(int)
或(long)
等。- 检查溢出:在执行可能导致溢出的操作之前进行检查,以确保不会发生截断。
示例代码:
#include <stdio.h>
#include <stdint.h>
int main() {
uint8_t a = 200;
uint8_t b = 100;
uint16_t sum;
// 使用一个更大的类型来避免截断
sum = (uint16_t)a + (uint16_t)b;
printf("Sum of a and b (no truncation): %u\n", sum);
return 0;
}
//在这个例子中,我们使用 uint16_t 类型来存储 a 和 b 的和,
//这样即使结果超过了 unsigned char 的表示范围,也不会发生截断。
5.小结
截断是 C 语言中一个常见的现象,特别是在处理不同类型之间的赋值时。了解截断的概念、原因以及如何避免它,可以帮助我们编写更可靠、更安全的代码。希望这篇文章对你有所帮助!