我们看到的最简单的 C++ 代码是如下形式:
int main()
{
std::cout << "Hello World!\n";
}
问题来了:如何在 UEFI 下面实现这种形式的代码?根据【参考1】,cout << n; 中,<< 是个运算符,n 是个变量,运算符应该接的是变量,所以 cout是个变量,但是在C++中这种高级变量叫做对象。cout 是一个对象。
因此,我们可以通过定义 cout 这个对象,然后定义 << 这个运算符即可。完整代码如下:
#include <UEFI/UEFI.h>
#include <type_traits>
#define EFI_ERROR(status) ((status) != EFI_SUCCESS)
EFI_SYSTEM_TABLE* gSystemTable;
void printInt(int value) {
CHAR16 out[32];
CHAR16* ptr = out;
static_assert(std::is_unsigned_v<char16_t>);
if (value == 0)
{
gSystemTable->ConOut->OutputString(gSystemTable->ConOut, u"0");
return;
}
ptr += 31;
*--ptr = 0;
int tmp = value;// >= 0 ? value : -value;
while (tmp)
{
*--ptr = '0' + tmp % 10;
tmp /= 10;
}
if (value < 0) *--ptr = '-';
gSystemTable->ConOut->OutputString(gSystemTable->ConOut, ptr);
}
class ostream {
public:
void operator<<(int x);
};
void ostream::operator<<(int x) {
printInt(x);
return ;
}
ostream cout;
EFI_STATUS
efi_main(EFI_HANDLE /*image*/, EFI_SYSTEM_TABLE* systemTable)
{
gSystemTable=systemTable;
cout << 122;
gSystemTable->ConOut->OutputString(gSystemTable->ConOut, u"\r\n");
return EFI_SUCCESS;
}
运行结果如下:
已经非常像了。接下来还有一个 std 的问题。这个可以通过 Namespace来实现。“编写程序过程中,名称(name)可以是符号常量、变量、函数、结构、枚举、类和对象等等。工程越大,名称互相冲突性的可能性越大。另外使用多个厂商的类库时,也可能导致名称冲突。为了避免,在大规模程序的设计中,以及在程序员使用各种各样的 C++ 库时,这些标识符的命名发生冲突,标准 C++ 引入关键字 namespace(命名空间/名字空间/名称空间),可以更好地控制标识符的作用域。
例如,我们在 C 语言中,通过 static 可以限制名字只在当前编译单元内可见,在 C++ 中我们通过 namespace 来控制对名字的访问。”【参考2】
修改代码如下形式:
namespace std {
class ostream {
public:
void operator<<(int x);
};
void ostream::operator<<(int x) {
printInt(x);
return ;
}
ostream cout;
}
namespace 是C++中的关键字,用来定义一个命名空间,语法格式为:
namespace name{
//variables, functions, classes
}
name是命名空间的名字,它里面可以包含变量、函数、类、typedef、#define 等,最后由{ }包围【参考3】。
我们就可以直接使用 std::cout << 122; 这种形式了。接下来,还有如何实现 std::cout << 122 << 13; 有兴趣的朋友可以继续研究。
参考:
- https://blog.csdn.net/u011386173/article/details/121085201
- https://baijiahao.baidu.com/s?id=1662580430712018597&wfr=spider&for=pc
- https://c.biancheng.net/view/2192.html