(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365)
原计划的50篇博客,终于完成了。可惜的是,现有的篇幅无法把最初设想的内容全部覆盖。因此,开发探索系列还会继续写下去,既然原定目标50篇已经达成,新的目标篇数就不设定了。只针对我感兴趣的各方面的内容,继续探索。
在日常的开发中,总会用到各种打印(print)函数。UEFI下的打印函数,其格式有点奇怪,和Windows及Linux下的print函数不大相同。而且又涉及到Ascii字符和Unicode字符的支持,在使用中总是犯一些小错,让人很是恼火。
因此,为了方便后面的开发,我准备将相关的打印函数整理出来,以备参考。
1OutputString()
最基本的打印输出函数,其他Print函数都是基于此函数构建的。其函数原型为:
typedef
EFI_STATUS
(EFIAPI *EFI_TEXT_STRING) (
IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,//指向
//EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL实例的指针
IN CHAR16 *String //以Null结尾的字符串
);
此函数向输出设备写入字符串,显示在当前光标处,是最基本的输出机制。
示例如下:
gST->ConOut->OutputString(gST->ConOut,L”Hello, UEFI World!\n\r”);
这是Simple Text Output Protocol最核心的函数,配合此Protocol的其他函数,比如SetAttribute等,可以实现彩色背景和彩色字体。在之前的博客中曾经展示过,可以做出与众不同的命令行式Sell程序。
2 格式化输出
PrintLib提供了格式化输出的支持函数,它支持所有Unicode和ASCII字符串。在Package的dsc文件中,一般都会提供这个库的编译。如下:
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
UEFI的格式化方式,与ANSI C的标准不尽相同,在使用的时候,很容易造成概念混淆。
格式化语法如下:
%[flags][width][.precision]type
[flags]
● – 左对齐标志,如果没有设置,则为右对齐
● 空格 对数字类型字符添加前置空格,对类型X,x和d有效
● + 符号前缀,显示数字的正负,对类型X,x和d有效,与空格同用时,忽略空格
● 0 以先导0补充数字左侧,常配合后续的width(宽度)使用,对类型X,x和d
有效;
● , 以千位分隔符表示数字,只对类型d有效,与标志0同用时,忽略0;
● L,l 将指定的数字以UINT64型打印,对类型X,x和d有效。如果不指定此标志,
则以int型打印;
注意:非上述标志都会被忽略掉
[width]
● * 由参数列表中的数字给出宽度。如Print(L”%0*d”,5,a)表示以宽度5表示变量
a, 不足由前导0补上;
● 数字 由此10进制数给出需要表示的宽度;
注意:如果width的值没有给出,缺省以0指定。
[.precision]
● * 由参数列表中的数字给出宽度;
● 数字 由此10进制数给出需要表示的精度;
注意:如果此域没有给出,缺省以0指定。
type
● % 打印个百分号出来
● c 打印Unicode字符。ASCII字符也可以使用此类型,只要保证其bits8…15为0;
● x 将需要打印的参数认为是无符号十进制数,以十六进制形式打印参数。与ANSI C标准不同;
● X 将需要打印的参数认为是无符号十进制数,以十六进制形式打印参数,同时以前导0填充。与ANSI C标准不同;
● d 将需要打印的参数认为是有符号十进制数,以十进制形式打印参数;
● p 需要打印的参数是指针(Void *),以无符号十六进制形式打印出指针地址;
● a 参数为指向ASCII字符串的指针,与ANSI C标准不同;
● S,s 参数为指向Unicode字符串的指针,与ANSI C标准不同;
● g 参数为指向GUID结构的指针,用来打印GUID的。与ANSI标准不同;
● t 参数为指向EFI_TIME结构的指针,以mm/dd/yyyy hh:mm的形式打印,不足位的以0填充。与ANSI C标准不同;
● r 参数为RETURN_STATUS值,将此值代表的含义转换为字符串,打印出来。与ANSI C标准不同。
以下为部分转换对照:(具体值的含义可参考EDKII代码中的\BaseTools\Source\C\Include\Common\UefiBaseTypes.h)
RETURN_SUCCESS: “Success”
RETURN_LOAD_ERROR: “Load Error”
RETURN_INVALID_PARAMETER: “Invalid Parameter”
RETURN_UNSUPPORTED: “Unsupported”
示例说明:
对于flags的’+’,虽然对type(类型)x和X都有效,不过因为x和X都是以无符号来处理参数的,个人觉得没有什么作用。
INTN a=-234;
Print(“a=%+d\n”,a);
Print(“a=0x%+x\n”,a);
输出为:
a=-234
a=0xFFFFFF16
比较常用,也容易搞错的类型是’a’、’S’和’s’。含义与ANSI中完全不同,主要用来区分UEFI下ANSI字符串和Unicode字符串。
CHAR8 * str=”Hello, UEFI World!\n”;
Print(L”%a”,str);
输出:
Hello,UEFI World!
在编程时,针对两种编码,在使用时需要注意。比如上述例子,习惯性会使用”%s”去打印,当然是什么都打印不出来的,因为str不是有效的Unicode字符串。
3 常用打印相关函数
UINTN EFIAPI Print(IN CONST CHAR* Format, …)
参数:
Format:以Null结尾的Unicode字符串
…:按格式化规则给定的变量参数列表
返回:
按格式输出变量到ConOut
函数说明:
按照Format中给出的格式化字符串,通过ConOut输出变量。输出变量的大小如果大于PcdUefiLibMaxPrintBufferSize,则按照此长度截断,输出到ConOut。
UINTN EFIAPI PrintXY ( IN UINTN PointX,
IN UINTN PointY,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL * ForeGround,
IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BackGround,
IN CONST CHAR16 * Format,
…
)
参数:
PointX: 显示字符串位置的X坐标
PointY: 显示字符串位置的Y坐标
ForeGround: 字符串显示的字体颜色,可设置为NULL,直接使用ConOut设备的
背景色
BackGround: 字符串显示的字体背景颜色,可设置为NULL,直接使用ConOut设
备的背景色
Format: 以NULL结尾的Unicode格式化字符串。
…:按格式化规则给定的变量参数列表
返回:
按格式输出变量
函数说明:
按照Format中给出的格式化字符串,在图形模式下,通过ConOutputHandle输出变量,输出位置在(PointX,PointY)。如果输出位置超过显示规定的边缘,则显示的图像会被截断。可配合HII来实现显示。
UINTN EFIAPI AsciiPrint ( IN CONST CHAR8 * Format, … )
参数:
Format:以Null结尾的ASCII字符串
…:按格式化规则给定的变量参数列表
返回:
按格式输出变量到ConOut
函数说明:
按照Format中给出的格式化字符串,通过ConOut输出变量。输出变量的大小如果大于PcdUefiLibMaxPrintBufferSize,则按照此长度截断,输出到ConOut。
其他函数:
UINTN EFIAPI StrLen ( IN CONST CHAR16 * String ) ;
UINTN EFIAPI AsciiStrLen ( IN CONST CHAR8 * String ) ;
CHAR16* EFIAPI StrCpy ( OUT CHAR16 * Destination, IN CONST CHAR16 * Source );
CHAR8* EFIAPI AsciiStrCpy ( OUT CHAR8 * Destination, IN CONST CHAR8 * Source );
INTN EFIAPI StrCmp ( IN CONST CHAR16 * FirstString, IN CONST CHAR16 * SecondString );
INTN EFIAPI AsciiStrCmp ( IN CONST CHAR8 * FirstString, IN CONST CHAR8 * SecondString );
CHAR8* EFIAPI UnicodeStrToAsciiStr ( IN CONST CHAR16 * Source, OUT CHAR8 * Destination );
CHAR16* EFIAPI AsciiStrToUnicodeStr ( IN CONST CHAR8 * Source, OUT CHAR16 * Destination );