本课目标
完成本课后,你将能够:
-
深入理解预定义整数类型与机器整数类型的区别
-
掌握用户定义整数的范围约束与存储优化
-
熟练应用模类型的回绕特性与位运算场景
-
处理整数运算的溢出、饱和与异常策略
-
选择适合嵌入式与高性能场景的整数方案
一、预定义整数类型
1.1 标准整数类型族
Ada预定义了完整的整数类型层次:
-- 根整数类型(理论无限精度,实际受实现限制)
type Universal_Integer is range -(2**63) .. 2**63-1; -- 概念性
-- 标准预定义整数
type Integer is range -(2**31) .. 2**31-1; -- 通常32位
type Natural is range 0 .. Integer'Last; -- 非负整数
type Positive is range 1 .. Integer'Last; -- 正整数
-- 长整数与短整数(实现定义)
type Long_Integer is range -(2**63) .. 2**63-1; -- 通常64位
type Short_Integer is range -(2**15) .. 2**15-1; -- 通常16位
type Short_Short_Integer is range -(2**7) .. 2**7-1; -- 通常8位
关键洞察: Integer 的具体范围由编译器实现决定,但保证至少16位。GNAT中通常为32位。
1.2 整数类型属性全解
procedure Integer_Attributes is
X : Integer := 100;
begin
-- 范围属性
Put_Line ("Integer'First = " & Integer'Image (Integer'First));
Put_Line ("Integer'Last = " & Integer'Image (Integer'Last));
Put_Line ("Integer'Range = " & Integer'Image (Integer'First) &
" .. " & Integer'Image (Integer'Last));
-- 大小属性
Put_Line ("Integer'Size = " & Integer'Image (Integer'Size) & " bits");
Put_Line ("Integer'Object_Size = " &
Integer'Image (Integer'Object_Size));
-- 运算属性(基属性)
Put_Line ("X'Valid = " & Boolean'Image (X'Valid)); -- 检查值是否有效
Put_Line ("100'Image = " & 100'Image); -- " 100"
Put_Line ("Integer'Value (""42"") = " &
Integer'Image (Integer'Value ("42")));
-- 机器表示
Put_Line ("Integer'Machine_Radix = " &
Integer'Image (Integer'Machine_Radix)); -- 通常为2
end Integer_Attributes;
整数属性速查表:
| 属性 | 返回值 | 说明 |
|---|---|---|
'First | 最小值 | 类型下界 |
'Last | 最大值 | 类型上界 |
'Range | 范围 | First .. Last |
'Size | 位数 | 最小存储位数 |
'Object_Size | 位数 | 实际分配位数(可能大于Size) |
'Value | 整数 | 从字符串解析 |
'Image | 字符串 | 转为字符串(前导空格) |
'Width | 整数 | 图像字符串最大长度 |
'Valid | 布尔 | 值是否在范围内 |
'Machine_Radix | 整数 | 基数(通常为2) |
'Machine_Emin | 整数 | 最小指数(浮点用) |
二、用户定义整数类型
2.1 范围约束整数
-- 基本语法:type 名称 is range 下界 .. 上界;
-- 嵌入式常见定义
type Byte is range -128 .. 127; -- 8位有符号
type UByte is range 0 .. 255; -- 8位无符号(用Natural更好)
type Word is range 0 .. 65_535; -- 16位无符号
type SWord is range -32_768 .. 32_767; -- 16位有符号
type DWord is range 0 .. 4_294_967_295; -- 32位无符号
type SDWord is range -2_147_483_648 .. 2_147_483_647; -- 32位有符号
-- 特定应用定义
type Percentage is range 0 .. 100; -- 百分比
type Angle_Degrees is range 0 .. 359; -- 角度(0-359)
type Year is range 1900 .. 2100; -- 年份范围
type Month is range 1 .. 12; -- 月份
type Day_Of_Month is range 1 .. 31; -- 日(需配合月份验证)
存储优化:编译器自动选择最小足够存储:
| 类型定义 | GNAT通常选择 | 说明 |
|---|---|---|
range -128 .. 127 | Signed_8 | 8 位 |
range 0 .. 255 | Unsigned_8 | 8 位 |
range -32_768 .. 32_767 | Signed_16 | 16 位 |
range 0 .. 65_535 | Unsigned_16 | 16 位 |
range -(2**31) .. 2**31-1 | Signed_32 | 32 位 |
2.2 大小子句强制存储
当需要精确控制存储大小时,使用 Size 子句:
package Precise_Types is
type Byte is range -128 .. 127;
for Byte'Size use 8; -- 强制8位存储
type Status_Flags is range 0 .. 255;
for Status_Flags'Size use 8;
pragma Pack (Status_Flags); -- 紧凑排列(通常与Size配合)
-- 记录中的位域控制
type Control_Register is record
Enable : Boolean;
Interrupt : Boolean;
Mode : range 0 .. 3; -- 2位
Reserved : range 0 .. 15; -- 4位
end record;
for Control_Register use record
Enable at 0 range 0 .. 0; -- 位0
Interrupt at 0 range 1 .. 1; -- 位1
Mode at 0 range 2 .. 3; -- 位2-3
Reserved at 0 range 4 .. 7; -- 位4-7
end record;
for Control_Register'Size use 8; -- 总共8位 = 1字节
end Precise_Types;
三、模类型(Modular Types)
3.1 模类型的核心特性
模类型是无符号整数,运算自动回绕(wrap-around),无溢出异常:
-- 定义:type 名称 is mod 模数;
-- 值域:0 到 模数-1
type Byte_Mod is mod 2**8; -- 0 .. 255,256回绕到0
type Word_Mod is mod 2**16; -- 0 .. 65535
type Bit_Field is mod 2**32; -- 32位位域
-- 使用
B : Byte_Mod := 255;
B := B + 1; -- 结果为0,无异常!
B := B - 1; -- 回到255
-- 位运算(模类型的优势)
Flags : Byte_Mod := 2#1010_1010#;
Mask : constant Byte_Mod := 2#0000_1111#;
Result := Flags and Mask; -- 按位与:2#0000_1010#
Result := Flags or Mask; -- 按位或
Result := Flags xor Mask; -- 按位异或
Result := not Flags; -- 按位取反(在范围内)
Result := Flags shl 2; -- 左移(GNAT特定)
Result := Flags shr 1; -- 右移(GNAT特定)
3.2 模类型 vs 有符号整数
| 特性 | 模类型(mod) | 有符号整数(range) |
|---|---|---|
| 值域 | 0 .. 模数-1 | 负值 .. 正值 |
| 溢出行为 | 自动回绕 | 抛出 Constraint_Error |
| 位运算 | 原生支持 | 需转换 |
| 适用场景 | 位掩码、哈希、循环计数 | 通用算术、物理量 |
| 与负数运算 | 禁止(编译错误) | 允许 |
3.3 模类型实战:位掩码
package GPIO_Driver is
type Pin_Number is range 0 .. 31;
-- 32位寄存器,每位控制一个引脚
type Pin_Mask is mod 2**32;
-- 常量定义
PIN_0 : constant Pin_Mask := 2**0;
PIN_1 : constant Pin_Mask := 2**1;
PIN_LED: constant Pin_Mask := 2**13; -- 板载LED
PIN_ALL: constant Pin_Mask := Pin_Mask'Last;
-- 操作子程序
function Make_Mask (Pin : Pin_Number) return Pin_Mask
is (2**Natural (Pin));
procedure Set_Pins (Mask : Pin_Mask); -- 置位
procedure Clear_Pins (Mask : Pin_Mask); -- 清零
procedure Toggle_Pins(Mask : Pin_Mask); -- 翻转
-- 使用示例
-- Set_Pins (PIN_LED or PIN_0); -- 同时设置LED和引脚0
end GPIO_Driver;
package body GPIO_Driver is
-- 假设硬件寄存器地址
GPIO_SET : Pin_Mask
with Address => System'To_Address (16#4000_1000#), Volatile;
GPIO_CLR : Pin_Mask
with Address => System'To_Address (16#4000_1004#), Volatile;
GPIO_TOGGLE: Pin_Mask
with Address => System'To_Address (16#4000_1008#), Volatile;
procedure Set_Pins (Mask : Pin_Mask) is
begin
GPIO_SET := Mask; -- 写1置位
end Set_Pins;
procedure Clear_Pins (Mask : Pin_Mask) is
begin
GPIO_CLR := Mask; -- 写1清零
end Clear_Pins;
procedure Toggle_Pins (Mask : Pin_Mask) is
begin
GPIO_TOGGLE := Mask; -- 写1翻转
end Toggle_Pins;
end GPIO_Driver;
四、整数运算与溢出处理
4.1 标准运算与溢出检查
procedure Integer_Operations is
type Small is range -100 .. 100;
X, Y, Z : Small;
begin
X := 50;
Y := 60;
-- 加法(可能溢出)
Z := X + Y; -- 110 > 100,抛出Constraint_Error!
-- 减法(可能下溢)
Z := X - Y; -- -50 - 60 = -110 < -100,异常!
-- 乘法(高风险)
Z := X * 3; -- 150 > 100,异常!
-- 除法(除零检查)
Z := X / 0; -- 除零异常!
-- 幂运算
Z := 2 ** 7; -- 128 > 100,异常!
end Integer_Operations;
4.2 溢出处理策略
策略1:使用更大范围类型
type Safe_Small is range -10_000 .. 10_000;
X, Y : Safe_Small := 100;
Z : Safe_Small := X * Y; -- OK,不会溢出
策略2:显式检查(防御式编程)
procedure Safe_Add (A, B : in Small; Result : out Small; OK : out Boolean) is
Temp : Integer; -- 使用更大范围临时存储
begin
Temp := Integer (A) + Integer (B);
if Temp in Small'Range then
Result := Small (Temp);
OK := True;
else
OK := False; -- 调用者处理溢出
-- 或:Result := Small'Last; -- 饱和处理
end if;
end Safe_Add;
策略3:模类型自动回绕
type Wrapping_Byte is mod 256;
X, Y : Wrapping_Byte := 200;
Z : Wrapping_Byte := X + Y; -- 400 mod 256 = 144,无异常
策略4:饱和运算(自定义)
function Saturating_Add (A, B : Small) return Small is
Temp : Integer := Integer (A) + Integer (B);
begin
if Temp > Small'Last then
return Small'Last; -- 正饱和
elsif Temp < Small'First then
return Small'First; -- 负饱和
else
return Small (Temp);
end if;
end Saturating_Add;
4.3 禁用溢出检查(危险!)
pragma Suppress (Overflow_Check); -- 全局禁用(不推荐)
-- 或局部禁用
procedure Fast_But_Unsafe is
pragma Suppress (Overflow_Check);
begin
-- 此区域内无溢出检查,回绕行为未定义!
null;
end Fast_But_Unsafe;
警告:仅在绝对必要时使用,且必须证明不会溢出。
五、机器整数与表示
5.1 预定义机器整数
Interfaces 包提供精确位宽的机器整数:
with Interfaces;
procedure Machine_Integers is
use Interfaces;
-- 有符号
X8 : Integer_8 := -128; -- 8位
X16 : Integer_16 := -32768; -- 16位
X32 : Integer_32 := -2**31; -- 32位
X64 : Integer_64 := -2**63; -- 64位
-- 无符号
U8 : Unsigned_8 := 255; -- 8位
U16 : Unsigned_16 := 65535; -- 16位
U32 : Unsigned_32 := 2**32-1; -- 32位
U64 : Unsigned_64 := 2**64-1; -- 64位
begin
-- 与C代码交互时直接使用这些类型
null;
end Machine_Integers;
5.2 表示子句高级应用
package Hardware_Types is
type Device_Status is record
Powered_On : Boolean;
Error_Flag : Boolean;
Busy : Boolean;
Data_Ready : Boolean;
Error_Code : range 0 .. 15;
end record;
-- 强制位布局,匹配硬件寄存器
for Device_Status use record
Powered_On at 0 range 0 .. 0;
Error_Flag at 0 range 1 .. 1;
Busy at 0 range 2 .. 2;
Data_Ready at 0 range 3 .. 3;
Error_Code at 0 range 4 .. 7;
end record;
for Device_Status'Size use 8;
pragma Pack (Device_Status);
-- 验证大小
pragma Compile_Time_Error
(Device_Status'Size /= 8, "Status must be 8 bits");
end Hardware_Types;
六、完整示例:安全计数器
------------------------------------------------------------------------------
-- Safe_Counter --
-- --
-- 演示整数类型、溢出处理与模类型的综合应用 --
------------------------------------------------------------------------------
generic
Initial_Value : Integer := 0;
Min_Value : Integer := Integer'First;
Max_Value : Integer := Integer'Last;
package Safe_Counter is
type Counter is private;
-- 创建计数器
function Create (Start : Integer := Initial_Value) return Counter
with Pre => Start in Min_Value .. Max_Value;
-- 递增(饱和或异常)
procedure Increment (C : in out Counter; By : in Positive := 1);
-- 递减(饱和或异常)
procedure Decrement (C : in out Counter; By : in Positive := 1);
-- 当前值
function Value (C : Counter) return Integer;
-- 检查是否饱和
function Is_Saturated (C : Counter) return Boolean;
-- 溢出异常
Overflow_Error : exception;
Underflow_Error : exception;
private
type Counter is record
Val : Integer range Min_Value .. Max_Value;
Saturated : Boolean := False;
end record;
end Safe_Counter;
package body Safe_Counter is
function Create (Start : Integer := Initial_Value) return Counter is
begin
return (Val => Start, Saturated => False);
end Create;
procedure Increment (C : in out Counter; By : in Positive := 1) is
Temp : Integer;
begin
if C.Saturated then
return; -- 保持饱和状态
end if;
Temp := Integer (C.Val) + By;
if Temp > Max_Value then
C.Val := Max_Value;
C.Saturated := True;
raise Overflow_Error with "Counter saturated at maximum";
else
C.Val := Temp;
end if;
end Increment;
procedure Decrement (C : in out Counter; By : in Positive := 1) is
Temp : Integer;
begin
if C.Saturated then
return;
end if;
Temp := Integer (C.Val) - By;
if Temp < Min_Value then
C.Val := Min_Value;
C.Saturated := True;
raise Underflow_Error with "Counter saturated at minimum";
else
C.Val := Temp;
end if;
end Decrement;
function Value (C : Counter) return Integer is
begin
return C.Val;
end Value;
function Is_Saturated (C : Counter) return Boolean is
begin
return C.Saturated;
end Is_Saturated;
end Safe_Counter;
七、本课总结
-
预定义整数:
Integer/Natural/Positive等,范围由实现决定 -
用户定义整数:
type T is range A .. B,编译器自动优化存储 -
模类型:
type T is mod N,无符号、自动回绕、原生位运算 -
溢出策略:大类型、显式检查、模回绕、饱和运算、禁用检查(危险)
-
机器整数:
Interfaces包提供Integer_8/16/32/64等精确位宽类型
八、课后练习
1.类型设计:为"秒表"设计类型,支持0-5999秒(99分59秒),溢出归零。
2.位域操作:实现一个8位状态寄存器,包含3个标志位和5位错误码字段。
3.饱和运算:为 Percentage (0-100)类型实现完整的饱和算术运算包。
4.哈希函数:使用模类型实现简单的32位FNV-1a哈希算法。
5.溢出分析:分析以下代码的潜在溢出问题并提出修复方案:
type Index is range 1 .. 10_000;
type Array_Type is array (Index) of Integer;
procedure Sum (A : Array_Type; Total : out Integer) is
begin
Total := 0;
for I in A'Range loop
Total := Total + A (I);
end loop;
end Sum;
九、下节预告
第10课|浮点与定点类型
我们将:
-
深入IEEE 754浮点表示与精度问题
-
掌握用户定义浮点的精度与范围控制
-
理解定点类型的delta与范围约束
-
学习数值稳定性分析与误差控制策略
关键术语表
模类型:无符号整数类型,运算自动按模回绕
大小子句:
for T'Size use N,强制类型的存储位数表示子句:控制类型的内存布局,用于硬件寄存器映射
饱和运算:溢出时钳位到最大/最小值,而非异常或回绕
机器整数:
Interfaces包中定义的固定位宽整数类型