Skip to main content

14.整数类型

第14集《认识 C# 整数类型》

开场

大家好,我是村长。欢迎来到第14集。

上节课,我们学习了值类型和引用类型的区别。

今天,我们继续深入值类型,学习其中最常用的整数类型。

学完这集,你要能回答三个问题:

第一,整数类型到底是什么?

第二,C#有哪些整数类型?

第三,写代码的时候,到底应该选哪个?

尤其是第三个问题。很多初学者分不清:“存储年龄到底该用 byte 还是 int”

今天咱们就把这个问题一次讲明白。


本期内容 一、整数类型到底是什么? 二、C# 有哪些整数类型? 三、如何声明整型变量 四、如何选择整数类型?

一、整数类型到底是什么?

首先,把目光聚焦到"整数类型"这四个字上。

整数,就是不带小数点的数。

比如:

10
-100
0
2026

这些都是整数。

而这些

3.14 0.5 -2.8 3.0

都不是整数,是小数。

类型,本质上就是一组规则。

什么规则?规定如何对待数据的规则。如果你不理解这句话,可以回看第6集《数据类型到底是什么》。

所以,把整数和类型合在一起,

整数类型就是用来表示和处理整数的一套规则。

就这么简单。记住这句话,后面的内容全是从这句话长出来的。

二、C#的整数类型有哪些?

C#一共预定义了10种整数类型。每种类型都有三个关键属性:取值范围、内存空间,以及对应的 .NET类型。

取值范围:告诉你这个类型能存多大的数。

内存空间:表示该类型占多少位。

这里的位,是计算机存储信息的最小单位,英文叫bit, 1 位可以表示0 或 1两个数 2 位可以表示 0、1、2、3四个数, 8 位可以表示2⁸也就是 256 个数。

人们规定:8 位就是 1 个字节,所以16 位是 2 个字节,32 位是 4 个字节,以此类推。占用的字节越多,能够表示的整数范围越大;

.NET类型:是C#类型名称对应的完整类型名,比如 int 实际上是 System.Int32的别名,long 是 System.Int64的别名,二者完全等价。

例如:

int i1 = 100;
System.Int32 i2 = 100;

在这里,使用别名 int 更加简洁。

C#类型取值范围内存空间.NET 类型说明
sbyte-128 ~ 1278 位System.SByte有符号字节整型
byte0 ~ 2558 位System.Byte无符号字节整型
short-32,768 ~ 32,76716 位System.Int16短整型(有符号)
ushort0 ~ 65,53516 位System.UInt16短整型(无符号)
int-2,147,483,648 ~ 2,147,483,647(约21亿)32 位System.Int32整型(有符号)
uint0 ~ 4,294,967,295(约42亿)32 位System.UInt32整型(无符号)
long-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807(约922亿亿)64 位System.Int64长整型(有符号)
ulong0 ~ 18,446,744,073,709,551,615(约1844亿亿)64 位System.UInt64长整型(无符号)
nint平台相关平台相关System.IntPtr原生整型(有符号)
nuint平台相关平台相关System.UIntPtr原生整型(无符号)

10 种类型看起来有点多,但我们可以把它们分成五组:

  • 字节整型、短整型、整型、长整型、原生整型:

其中,原生整型比较特殊,主要用于底层操作,初学者暂时不用掌握。

所以本期视频真正需要重点掌握的,是前四组、共八种整型。

每组整型都可以分为有符号和无符号两种

  • 有符号整型:可以存储正整数、负整数和0。
  • 无符号整型:只能存储正整数和零,不能存储负整数。 举个例子 存储气温时,气温有正负之分。所以可以使用有符号的 sbyte
sbyte temperature = -10;

但如果用无符号的 byte:

byte temperature = -10;

就会报错。因为 byte不能表示负数。

无论是字节整型、短整型、整型、长整型,它们的根本区别只有一个:表示的整数范围不同。

【字节整型】 字节整型也叫“八位整型“

  • byte 是无符号八位整型。8个位全部用来表示数值,最多可以表示 2⁸ ,也就是 256 个数,所以可表示的整数范围是:0~255;
  • sbyte 是有符号8位整型,最高位表示正负号,剩余 7 位表示数值,所以可表示的整数范围是-128 ~ 127。 为什么是 -128,不是-127?这涉及二进制补码。今天先不展开,以后我会专门讲解。现在,你只需要记住这个范围。

【短整型】 短整型,也叫16 位整型。可以表示 2¹⁶ 个数:

  • short 是有符号 16 位整型,可表示的整数范围是:-32,768 ~ 32,767 (-3.2万 ~ 3.2万)
  • ushort 是无符号 16 位整型,可表示的整数范围是:0~65,535 (约 6.5 万)

【整型】 整型,也叫32 位整型。可以表示 2³² 个数:

  • int 是有符号 32 位整型,可表示的整数范围是 -21 亿 ~ 21 亿
  • uint 是无符号 32位整型,可表示的整数范围是:0 ~ 42亿

【长整型】 长整型,又叫64 位整型。可以表示 2⁶⁴ 个数:

  • long 是有符号 64 位整型。可表示的整数范围是-922亿亿 ~ 922亿亿
  • ulong 是无符号64 位整型。可表示的整数范围是0 ~1844亿亿

三、如何声明整型变量

了解了整数类型的取值范围后, 我们来动手声明这 8 种类型的变量

byte b1 = 128;
sbyte sb = -128;
short s = -128;
ushort us = 128;
int i = -128;
uint ui = 128;
long l = -128;
ulong ul = 128;

现在,把光标悬停在赋值符号左边的变量名 b1 上, IDE 提示:b1 是 byte 类型。

再把光标移到右边的数值 128 上,IDE 提示:128 是System.Int32,也就是int 类型。

赋值符号两侧的类型并不相同,为什么没有报错?

原来,这是因为编译器会对整数字面量 自动推断类型,并在赋值时进行隐式类型转换。

推断规则是:按 int 到 uint 再到 long 最后是 ulong 的顺序依次尝试,找到第一个能装下该数值的类型就停止。

128 在 int 范围内,所以被推断为 int。

如果你不想让编译器自动推断类型, 可以用字母后缀显式告诉编译器你要的类型 C#提供了三种类型后缀:U、L和 UL

uint ui1 = 128U;
long l1 = -128L;
ulong ul1 = 128UL;

在这里,

  • 后缀 U 告诉编译器,请按无符号整型处理。
  • 后缀 L 告诉编译器,请按有符号长整型处理。
  • 后缀 UL 告诉编译器,请按无符号长整型处理。

注意两点:

  1. 后缀不是"必须加",而是"需要时再加"。 大多数情况下,让编译器自动推断就可以,只有明确需要指定类型时才加后缀。
  2. 对于 byte、sbyte、short、ushort 这些小于 32 位的类型,C# 没有提供对应的类型后缀。通常直接写数字就可以,编译器会自动处理。

四、如何选择整数类型?

C#之所以提供了这么多整数类型。是因为现实中的数据需求,多种多样。

奇奇:那这么多类型,写代码的时候到底该选哪个?

村长:很简单,遇到选择障碍时,你只需问自己三个问题。

第一问:能不能装下?

这是最基本的问题。比如:你要保存全球人口,大概 50 亿。int 最大只有 21 亿,装不下;uint 最大 42 亿,也装不下。这时,只能用 long类型:

long worldPopulation = 5000000000L;  

所以第一原则非常简单:

先看取值范围,保证数据能装下。


第二问:好不好用?

能装下,不代表它是最合适的。

比如,使用 byte 存储年龄 18

byte age = 18;

正常人的年龄不超过 200 岁,并且没有负年龄,所以用 byte 存储年龄完全合法。

但问题是:年龄在程序里往往要参与计算:

byte age = 18;

byte nextAge = age + 1;

这时,代码报错了。 把光标放到红色波浪线上,提示说:无法将类型 Int隐式转换为 byte,这说明 age + 1 是 int 类型。

变量 age 是 byte 类型,但加 1 后却变成了 int 类型

为什么?因为在 C# 中,byteshort 等较小的整数类型,参与计算时,会自动提升为 int

所以:age + 1 的结果是 int类型,但却要把它赋值给一个byte变量,左右类型不匹配。同时,age + 1是一个表达式,不是字面量,不会发生隐式类型转换,所以报错。

byte nextAge = age + 1;

当然,你可以根据提示,按下 Alt + .强制把age+1转换成 byte类型。

byte nextAge = (byte)(age + 1);

但这样代码就变复杂了

如果一开始就用 int,不用 byte:

int age = 18;
int nextAge = age + 1;

一切会变得很顺畅,没有任何类型转换的麻烦。

奇奇:可 byte 只占 1 个字节,int 占 4 个字节,用 byte 不是更省内存吗?听起来更"高效"啊?

村长:这个问题问得非常好!

byte确实更省内存。但占用内存少,不代表运行效率就一定高。

选择数据类型,不能只看它占多少内存,还要看它用起来方不方便。

不只是年龄。月份、得分、数量,这些数字单独看都不大。

byte 能不能存?能。

是不是应该用 byte?不一定。

因为它们会被比较、被计算、作为数组索引、传给方法——一旦参与到这些操作里,

byte 就会让你多操心:强转、类型提升、编译报错……

用 int 就完全没这些烦恼。

所以,选择整数类型的第二个标准就是:

不仅能装下,还要好用。

不要为了省几个字节,把简单的代码写复杂,得不偿失

奇奇:我懂了。没有特殊需求,普通整数就优先使用int类型。

村长:没错!写代码优先追求清晰好懂,不要盲目抠那点内存。int 够用就用 int,不要上来就用 short、byte 把代码搞难懂,后期维护反而更麻烦。

第三问:有没有特殊格式要求?

有些数据,本身就有固定的格式要求,必须按 1 个字节、2 个字节或 4 个字节来表示。这时候不能只看"数字能不能装下",要遵守数据格式本身的要求。

比如 PNG 文件格式规定,文件开头有一个固定的 8 字节文件签名。读取时,必须按照规定的字节格式处理:

// 读取 PNG 文件头,规范要求就是 8 个字节
byte[] header = new byte[8];

所以第三个原则就是:

总结

最后总结一下:选择整数类型,就问自己三个问题

第一,能不能装下?

第二,好不好用?

第三,有没有特殊格式要求? 如果前两个问题的答案都是"没问题",第三个问题也没有特殊要求——那就用 int

日常开发中,大多数普通整数场景用 int 就够了;数值范围超过 int 时,再考虑 long;而 byte、short 这些类型,一般是在数据有特殊要求时再使用。

所以不要认为"数字小就一定用 byte",也不要认为"long 最大,就全部用 long"。

记住一句话:

整数类型,不是越小越好,也不是越大越好——而是选择适合当前场景的类型。

结束语

好了,整数类型我们搞明白了。

但现实世界里的数据,可不只有整数。

下集我们来认识C#里的浮点数类型。

听懂不算会,敲出来才算。

如果你觉得这集有收获,记得点赞、收藏、关注。

我是村长。咱们下期见!