GNAT中Get函数从字符串读取十六进制值的异常问题咨询
问题原因解析
Ada的Ada.Integer_Text_IO.Get存在两个关键重载版本,行为差异导致了你遇到的问题:
1. 文件输入版本 vs 字符串输入版本的行为区别
- 文件输入的
Get(File_Type, Integer):会自动识别Ada标准的基数标记格式(如16#...#),无论当前设置的输入基数是什么,都会按照标记指定的基数解析数值。 - 字符串输入的
Get(From => String, ...):默认使用当前的输入基数(默认是十进制)解析字符串,不会自动识别16#...#这种基数前缀。
对应你的测试现象:
- 输入
16#12#时,字符串版本的Get会以十进制解析开头的16,遇到非十进制字符#就停止解析,所以返回结果16。 - 输入纯十六进制值
F8时,因为默认基数是十进制,F不是合法的十进制数字,直接触发异常。
2. 原测试代码的额外问题
你的代码里未声明HexString变量,且使用Get(HexString)会在空白或非字母数字字符处截断输入,无法读取完整的16#12#格式字符串,应该改用Get_Line来读取完整输入。
解决方案
要让字符串版本的Get支持16#...#格式或纯十六进制值,可以手动处理基数前缀,并设置对应的解析基数:
with Ada.Text_IO; use Ada.Text_IO; with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; with Ada.Strings.Fixed; use Ada.Strings.Fixed; procedure hex is IntValue : Integer; Last : Positive; HexString_Buf : String(1..20); -- 定义足够大的缓冲区 Actual_Length : Natural; begin Put("Enter a hexadecimal string: "); Get_Line(HexString_Buf, Actual_Length); -- 读取完整输入行 declare Input : constant String := HexString_Buf(1..Actual_Length); begin -- 处理Ada风格的16#...#格式 if Input'Length >= 4 and then Input(1..3) = "16#" and then Input(Input'Last) = '#' then declare Hex_Part : constant String := Input(4..Input'Last - 1); begin Set_Base(16); -- 设置解析基数为十六进制 Get(From => Hex_Part, Item => IntValue, Last => Last); -- 验证是否整个十六进制部分都被正确解析 if Last /= Hex_Part'Last then raise Constraint_Error with "无效的十六进制字符"; end if; end; else -- 尝试直接解析纯十六进制字符串 begin Set_Base(16); Get(From => Input, Item => IntValue, Last => Last); if Last /= Input'Last then raise Constraint_Error with "输入包含无效字符"; end if; exception when others => raise Constraint_Error with "输入格式错误,请使用16#...#或纯十六进制数字"; end; end if; end; Put("转换后的整数值为: "); Put(IntValue, Width => 0); New_Line; Set_Base(10); -- 恢复默认的十进制基数 end hex;
代码关键点说明:
- 使用
Get_Line读取完整输入行,避免Get截断问题。 - 先判断输入是否符合
16#...#格式,提取中间的十六进制部分后再解析。 - 通过
Set_Base(16)强制以十六进制解析字符串,支持0-9、A-F(大小写均可)。 - 增加了输入有效性验证,确保整个字符串都被正确解析。
内容的提问来源于stack exchange,提问作者Erlo
相关产品推荐
相关产品推荐

