EDK2编写的UEFI应用仅打印读取文件最后一个字符问题排查
问题分析与修复方案
你的UEFI应用仅输出文件最后一个字符,核心问题出在字符类型不匹配和打印格式错误,具体问题及修复如下:
1. 缓冲区类型与打印格式不兼容
UEFI环境中Print函数的%s格式符要求传入CHAR16*(宽字符指针),但你的代码中:
- 定义的
Buffer是UINT8数组,存储单字节数据 - 直接用
%s打印UINT8数组时,会被解析为宽字符序列。单字节内容会被当作宽字符的低字节,高字节默认补0,形成的宽字符大多无效,直到最后一个字节后添加的单字节'\0',才会让最后一个字符被正确识别为宽字符,导致只输出最后一个内容。
2. 文件路径打印格式错误
代码中两处打印文件路径时误用了%c格式符:
Print(L"Failed to open %c in read mode.\n", FilePath); Print(L"Failed to get file size of %c.\n", FilePath);
%c用于打印单个字符,而FilePath是CHAR16*字符串,应该改为%s,否则只会打印路径的第一个字符。
修复后的完整代码
#include <Uefi.h> #include <Library/UefiApplicationEntryPoint.h> #include <Library/UefiLib.h> #include <Library/UefiBootServicesTableLib.h> #include <Protocol/SimpleFileSystem.h> #define BufferSize 1024 EFI_STATUS EFIAPI UefiMain(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE* SystemTable) { EFI_STATUS Status = EFI_SUCCESS; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL* SimpleFileSystem; EFI_FILE_PROTOCOL* RootDir; EFI_FILE_PROTOCOL* File = NULL; CHAR16 FilePath[] = L"\\HelloWorld.txt"; UINTN FileSize; // 改为CHAR16缓冲区,适配UEFI宽字符打印要求 CHAR16 Buffer[BufferSize / sizeof(CHAR16)]; // 定位文件系统协议 Status = gBS->LocateProtocol(&gEfiSimpleFileSystemProtocolGuid, NULL, (VOID **)&SimpleFileSystem); if (EFI_ERROR(Status)) { Print(L"Failed to locate simple file system protocol.\n"); return Status; } // 打开根目录 Status = SimpleFileSystem->OpenVolume(SimpleFileSystem, &RootDir); if (EFI_ERROR(Status)) { Print(L"Failed to open root directory of file system.\n"); return Status; } // 打开目标文件 Status = RootDir->Open(RootDir, &File, FilePath, EFI_FILE_MODE_READ, 0); if (EFI_ERROR(Status)) { Print(L"Failed to open %s in read mode.\n", FilePath); RootDir->Close(RootDir); return Status; } // 获取文件大小 Status = File->SetPosition(File, 0xFFFFFFFFFFFFFFFF); if (!EFI_ERROR(Status)) { Status = File->GetPosition(File, &FileSize); } if(EFI_ERROR(Status)) { Print(L"Failed to get file size of %s.\n", FilePath); File->Close(File); RootDir->Close(RootDir); return Status; } // 检查文件大小是否超出缓冲区容量 if (FileSize > sizeof(Buffer)) { Print(L"File size exceeds buffer capacity.\n"); File->Close(File); RootDir->Close(RootDir); return EFI_BUFFER_TOO_SMALL; } // 读取文件内容到缓冲区 Status = File->SetPosition(File, 0); if (!EFI_ERROR(Status)) { Status = File->Read(File, &FileSize, Buffer); } if (EFI_ERROR(Status)) { Print(L"Failed to read file content.\n"); File->Close(File); RootDir->Close(RootDir); return Status; } else { // 用宽字符终止符确保字符串正确结束 UINTN CharCount = FileSize / sizeof(CHAR16); if (CharCount < ARRAY_SIZE(Buffer)) { Buffer[CharCount] = L'\0'; } else { Buffer[ARRAY_SIZE(Buffer)-1] = L'\0'; } } // 关闭文件和目录 File->Close(File); RootDir->Close(RootDir); // 打印文件内容 Print(L"File content: %s\n", Buffer); return Status; }
关键修复说明
- 将
Buffer类型改为CHAR16,匹配UEFIPrint函数的宽字符要求 - 修正文件路径打印的格式符,把
%c改为%s - 使用宽字符终止符
L'\0'替代单字节'\0',保证字符串正确终止 - 增加缓冲区容量检查,避免越界访问
内容的提问来源于stack exchange,提问作者Shmurkio
相关产品推荐
相关产品推荐

