含非图形字符的Unbounded_String使用'Image'属性触发编码错误
问题原因
前两行调用Ada.Text_IO.Put_Line直接输出字符串的原始字节序列,不会对内容做UTF-8合法性校验,所以包含Ada.Characters.Latin_1.Reserved_128(十六进制0x80)的字符串能正常输出。
但Unbounded_String'Image属性在生成字符串的可读表示时,GNAT的实现会尝试将内部存储的字节解码为UTF-8格式。而0x80是单独的字节,不符合UTF-8编码规则(UTF-8单字节字符范围是0x00-0x7F,多字节字符的起始字节和后续字节有特定格式),因此触发ADA.STRINGS.UTF_ENCODING.ENCODING_ERROR异常。
解决方案
1. 自定义打印/Image函数绕过UTF验证
如果需要类似'Image的输出格式(比如带引号的字符串表示),可以自己实现函数,直接使用To_String提取原始字节,避免内置'Image的UTF校验:
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Ada.Text_IO; use Ada.Text_IO; function Unbounded_String_Image(US : Unbounded_String) return String is begin return """ & To_String(US) & """; end Unbounded_String_Image; -- 使用示例 Put_Line(Unbounded_String_Image(Text_Unbounded_String));
2. 将Latin-1字符转换为合法UTF-8编码
如果需要保留字符语义且兼容UTF-8,可以把Latin_1.Reserved_128(对应Unicode码点U+0080)转换为合法的UTF-8字节序列0xC2 0x80:
Text_String : constant String := "Non Graphic Character: " & Character'Val(16#C2#) & Character'Val(16#80#);
这样Unbounded_String'Image就能正常处理,因为输入是合法的UTF-8。
3. 封装通用打印逻辑简化代码
对于包含Unbounded_String的记录,可以编写通用打印函数,自动处理字段:
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with Ada.Text_IO; use Ada.Text_IO; type My_Record is record Id : Integer; Data : Unbounded_String; end record; procedure Print_Record(R : My_Record) is begin Put_Line("Id: " & R.Id'Image); Put_Line("Data: """ & To_String(R.Data) & """"); end Print_Record;
这种方式比手动逐个字段处理更简洁,同时避免'Image的UTF校验问题。
内容的提问来源于stack exchange,提问作者dalex78
相关产品推荐
相关产品推荐

