整数类型是什么
整数类型用于存储整数(没有小数部分的数字),包括正整数、负整数和零。
整数类型分类
根据取值范围的不同,C#提供了八种整数类型:
| 类型 | 术语 | 大小 | 范围 | 后缀 | 默认值 |
|---|---|---|---|---|---|
| sbyte | 字节整型 | 1字节(8位) | -128 到 127 | 0 | |
| byte | 字节整型 | 1字节(8位) | 0 到 255 | 0 | |
| short | 短整型 | 2字节(16位) |
-32,768 到 32,767
|
0 | |
| ushort | 短整型 | 2字节(16位) |
0 到 65,535
|
0 | |
| int | 整型 | 4字节(32位) | -2,147,483,648 到 2,147,483,647 | 0 | |
| uint | 整型 | 4字节(32位) | 0 到 4,294,967,295 | u/U | 0 |
| long | 长整型 | 8字节(64位) | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 | l/L | 0L |
| ulong | 长整型 | 8字节(64位) | 0 到 18,446,744,073,709,551,615 | ul/UL | 0UL |
声明整型的语法
sbyte(8位有符号整数):
sbyte mySByte = -100;
byte(8位无符号整数):
byte myByte = 200;
short(16位有符号整数):
short myShort = -10000;
ushort(16位无符号整数):
ushort myUShort = 30000;
int(32位有符号整数):
int myInt = 1000000;
声明整型的语法(后缀)
声明uint(32位无符号整数):
uint myUInt = 2000000000;
uint myUInt = 2000000000U;
声明long(64位有符号整数):
long myLong = 1000000000000;
long myLong = 1000000000000L;
声明ulong(64位无符号整数):
ulong myULong = 1000000000000000000;
ulong myULong = 1000000000000000000UL;
关于添加后缀的原因
C# 编译器默认将整数字面量视为 int 类型(32 位有符号整数),如2000000000默认被视为“int”类型,不加后缀会导致编译错误:"整数太大,无法用 int 类型表示"。
- U:当数字较大时(接近或超过20亿),需要明确指定为无符号整数类型,这就是使用U后缀的原因。
- L:后缀显式告诉编译器:"这是 long 类型"。提高代码可读性,明确表示处理大数字。
// 错误写法(不加L)
long myLong = 1000000000000; // 编译错误:数字太大
// 正确写法(加L后缀)
long myLong = 1000000000000L; // 正确
byte与int比较
在 C# 中存储年龄时,选择 byte 还是 int 取决于具体场景和需求。下面我将详细分析两种选择的优缺点,并提供实际建议。
对比分析表
| 特性 | byte (推荐) | int (常用) |
|---|---|---|
| 内存占用 | 1字节 ✅ | 4字节 ❌ |
| 取值范围 | 0-255 (0-120 完全覆盖) ✅ | -20亿到+20亿 (远超需求) ❌ |
| 性能影响 | 微小优势 ✅ | 良好 ⚠️ |
| 类型转换 | 需要显式转换 ❌ | 无需转换 ✅ |
| 代码可读性 | 明确表示小范围数值 ✅ | 通用但不够精确 ⚠️ |
| 默认类型兼容 | 不兼容大多数API ❌ | 完美兼容 ✅ |
| 最佳适用场景 | 内存敏感应用、大数据集 | 通用开发、初学阶段 |
使用 byte 的优势
byte age = 25; // 明确表示年龄是小范围值,推荐首选
优点:
内存高效:1字节 vs int的4字节(节省75%内存)
范围精确:0-255 完美覆盖人类年龄范围(0-120)
语义明确:清晰表明这是小范围非负整数
-
大数据优势:存储百万用户年龄可节省约 2.86MB 内存
// 100万用户年龄存储 byte[] agesByte = new byte[1_000_000]; // 占用 0.95 MB int[] agesInt = new int[1_000_000]; // 占用 3.81 MB
缺点:
- 需要显式类型转换
- 不兼容期望int类型的API
- 超出255会抛出异常
使用 int 的优势
int age = 25; // 默认整数类型,传统选择
优点:
- 无需转换:直接用于数学运算
- API兼容:完美匹配大多数框架方法
- 开发便捷:初学者友好
- 范围安全:永不溢出(对年龄而言)
缺点:
- 内存浪费(每个年龄多占3字节)
- 语义不够精确(可表示负数和极大值)
使用场景
INT使用场景
日常使用优先默认选择int:除非有特殊需求,否则优先使用int
- 大多数API使用int
- 性能最佳(32位系统优化)
- 范围足够日常使用(±21亿)
BYTE使用场景
内存敏感场景使用byte/sbyte 如:
- 大型数组
- 如图像处理
- 网络传输:使用最小必要类型
byte[] imageData = new byte[1024 * 1024]; // 1MB
LONG使用场景
需要大范围整数使用long(最大支持9EB)或ulong,如:
- 文件大小
- 科学计算
long fileSize = 15L * 1024 * 1024 * 1024; // 15GB
UINT使用场景
无符号数仅无符号数场景,使用uint,如:
- 颜色值(ARGB):
uint color = 0xFFAABBCC; // 带透明度的颜色值
- 位掩码操作:uint/ulong
const uint ReadPermission = 0b0001;
const uint WritePermission = 0b0010;
uint userPermissions = ReadPermission | WritePermission;
- 类型转换时注意范围检查
- 使用数字分隔符提高大数可读性
- 涉及金融计算时使用
decimal而非整数类型
数字分隔符
c#允许在数字字面量中使用下划线 _ 作为分隔符以提高代码可读性。
long bigNumber = 9_223_372_036_854_775_807; // 提高可读性
- 数字分隔符 _ 仅用于提升代码可读性
- 编译时会完全忽略。
- 不改变数值的实际大小
使用规则
1.除去首尾,可在一个整数的任意位置添加分割符
int valid = 123_456; // ✅ 合法
int invalid = _123; // ❌ 错误:不能在开头
int invalid = 123_; // ❌ 错误:不能在结尾
2.可以连续使用两个下划线,禁止连续使用三个下划线
int valid = 1__2__3; // ✅ 合法(但建议避免过度使用)
int invalid = 1___23; // ❌ 错误:连续三个下划线
3.分隔符兼容各种进制
int dec = 1_000_000; // ✅ 十进制整数
double flt = 1_000.000_001; // ✅ 浮点数
decimal mon = 1_000_000.99m; // ✅ 十进制数
int hex = 0xDEAD_BEEF; // ✅ 十六进制
int bin = 0b1010_0101_1100; // ✅ 二进制
常见应用场景
// 大数值分段
long worldPopulation = 8045311447; // 难以阅读
long worldPopulation = 8_045_311_447; // 立即理解为"80亿"
//浮点数分段
double pi = 3.141_592_653_589_793;// π 的近似值
//金融数值
decimal nationalDebt = 31_456_932_742_893.27m;// 百万美元金额
//二进制
uint ipMask = 0b1111_1111_1111_1111_0000_0000_0000_0000;// IP地址掩码
//十六进制数据分组
int transparentRed = 0x80_FF_00_00;// 颜色值(ARGB)
// 电话号码
long customerPhone = 1_800_555_1212;
// 产品代码
ulong productCode = 12_3456_7890_1234_5678;
//分隔符与类型后缀:
long big = 1_000_000_000_000L; // ✅ L后缀在下划线后
//科学计数法:
double avogadro = 6.022_140_857e23; // ✅ 下划线在指数部分前
分组策略:
- 十进制:每3位分组(千位分隔)
- 十六进制:每4位分组(半字节/nibble)
- 二进制:每4位或8位分组
一致性原则:
int x = 10_0000; // 混合分组不一致(不推荐)
int x = 100_000; // 标准千位分隔,(推荐)
避免过度使用:
int overSeparated = 1_0_0_0_0; // 过度分隔(不推荐)
int readable = 100_000;// 适度分隔(推荐)
整数的除法运算
整数除法会导致小数点被截断的行为。
示例
int n = 10 / 3;
Console.Write(n); //结果是3,而不是3.333333333
代码行为分析
-
操作数:
10和3都是int类型。int / int,输出仍是int,类型未改变。 -
运算规则:当两个整数相除时,C# 执行整数除法,结果仍是
int类型,小数部分直接丢弃(不是四舍五入)。 -
结果:
10 / 3 = 3(余数 1 被丢弃)。
示例:隐式转换
double n = 10 / 3;
Console.Write(n); //结果是3.0,而不是3。此时发生了**隐式转换**(`int` → `double`),但除法本身仍是整数除法。
示例:浮点数结果
double correct1 = 10.0 / 3; // 10.0 是 double,触发浮点除法 → 3.333...
double correct2 = 10 / 3.0; // 3.0 是 double → 3.333...
double correct3 = (double)10 / 3; // 显式转换其中一个操作数
示例:decimal 的除法
decimal 会保留小数,但必须所有操作数都是 decimal:
decimal n = 10m / 3m; // 结果是 3.3333333333333333333333333333
总结
| 代码 | 运算类型 | 结果 | 是否涉及转换 |
|---|---|---|---|
int n = 10 / 3; |
整数除法 | 3 |
❌ 否 |
double n = 10 / 3; |
整数除法 + 隐式转换 | 3.0 |
✅ 是(结果转换) |
double n = 10.0 / 3; |
浮点除法 | 3.333... |
❌ 否(操作数类型提升) |
问题及修正方法
| 问题类型 | 修正方法 |
|---|---|
| 整数除法截断 | 至少一个操作数转为 double/decimal
|
| 浮点数精度问题 | 使用 double 或 decimal
|
| 输入安全处理 | 用 TryParse 替代 Parse
|
| 四舍五入需求 | 使用 Math.Round
|